Skip to content

Commit cfaec2a

Browse files
committed
re add spin_lock
1 parent 6d3ca5a commit cfaec2a

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

src/sync/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,5 @@ cfg_unstable! {
192192

193193
pub(crate) mod waker_set;
194194
pub(crate) use waker_set::WakerSet;
195+
pub(crate) mod spin_lock;
196+
pub(crate) use spin_lock::Spinlock;

src/sync/spin_lock.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use std::cell::UnsafeCell;
2+
use std::ops::{Deref, DerefMut};
3+
use std::sync::atomic::{AtomicBool, Ordering};
4+
5+
use crossbeam_utils::Backoff;
6+
7+
/// A simple spinlock.
8+
#[derive(Debug)]
9+
pub struct Spinlock<T> {
10+
locked: AtomicBool,
11+
value: UnsafeCell<T>,
12+
}
13+
14+
unsafe impl<T: Send> Send for Spinlock<T> {}
15+
unsafe impl<T: Send> Sync for Spinlock<T> {}
16+
17+
impl<T> Spinlock<T> {
18+
/// Returns a new spinlock initialized with `value`.
19+
pub const fn new(value: T) -> Spinlock<T> {
20+
Spinlock {
21+
locked: AtomicBool::new(false),
22+
value: UnsafeCell::new(value),
23+
}
24+
}
25+
26+
/// Locks the spinlock.
27+
pub fn lock(&self) -> SpinlockGuard<'_, T> {
28+
let backoff = Backoff::new();
29+
while self.locked.compare_and_swap(false, true, Ordering::Acquire) {
30+
backoff.snooze();
31+
}
32+
SpinlockGuard { parent: self }
33+
}
34+
}
35+
36+
/// A guard holding a spinlock locked.
37+
#[derive(Debug)]
38+
pub struct SpinlockGuard<'a, T> {
39+
parent: &'a Spinlock<T>,
40+
}
41+
42+
unsafe impl<T: Send> Send for SpinlockGuard<'_, T> {}
43+
unsafe impl<T: Sync> Sync for SpinlockGuard<'_, T> {}
44+
45+
impl<'a, T> Drop for SpinlockGuard<'a, T> {
46+
fn drop(&mut self) {
47+
self.parent.locked.store(false, Ordering::Release);
48+
}
49+
}
50+
51+
impl<'a, T> Deref for SpinlockGuard<'a, T> {
52+
type Target = T;
53+
54+
fn deref(&self) -> &T {
55+
unsafe { &*self.parent.value.get() }
56+
}
57+
}
58+
59+
impl<'a, T> DerefMut for SpinlockGuard<'a, T> {
60+
fn deref_mut(&mut self) -> &mut T {
61+
unsafe { &mut *self.parent.value.get() }
62+
}
63+
}
64+
65+
#[test]
66+
fn spinlock() {
67+
use std::sync::Arc;
68+
69+
use crate::sync::{Spinlock};
70+
use crate::task;
71+
72+
task::block_on(async {
73+
74+
let m = Arc::new(Spinlock::new(0));
75+
let mut tasks = vec![];
76+
77+
for _ in 0..10 {
78+
let m = m.clone();
79+
tasks.push(task::spawn(async move {
80+
*m.lock() += 1;
81+
}));
82+
}
83+
84+
for t in tasks {
85+
t.await;
86+
}
87+
assert_eq!(*m.lock(), 10);
88+
})
89+
}

0 commit comments

Comments
 (0)