-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.rs
68 lines (60 loc) · 2.28 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use crate::hint;
use crate::sync::atomic::{AtomicBool, Ordering};
#[cfg(test)]
mod tests;
pub struct SpinLockGuard<'a, T> {
lock: &'a SpinLock<T>,
}
impl<'a, T> Drop for SpinLockGuard<'a, T> {
fn drop(&mut self) {
self.lock.locked.store(false, Ordering::Release);
}
}
impl<'a, T> Deref for SpinLockGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// SAFETY: The existence of this guard means we own the data. Because we have a `&self`, no
// one else has a `&mut self`, so no one has a `&mut Self::Target`, so creating a
// `&Self::Target` is safe.
unsafe { &*self.lock.data.get() }
}
}
impl<'a, T> DerefMut for SpinLockGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
// SAFETY: The existence of this guard means we own the data. Because we have a `&mut
// self`, no one else has a reference to `self`, so no one has a reference to
// `Self::Target`, so creating a `&mut Self::Target` is safe.
unsafe { &mut *self.lock.data.get() }
}
}
// SAFETY: If we're sharing the lock then the other thread can't get a `T` - only a `&/&mut T` so
// we just need `T` to be `Sync`. The locking mechanism ensures that two shared versions don't get
// mutable access concurrently.
unsafe impl<T> Sync for SpinLock<T> where T: Sync {}
pub struct SpinLock<T> {
data: UnsafeCell<T>,
locked: AtomicBool,
}
impl<T> SpinLock<T> {
pub fn new(data: T) -> Self {
Self {
data: UnsafeCell::new(data),
locked: AtomicBool::new(false),
}
}
pub fn lock(&self) -> SpinLockGuard<T> {
// ORDERING: Acquiring a `false` here means that the `SpinLockGuard::drop` that stored it
// (with `Release` ordering), and everything before that, has already happened. That means
// that the previous owner has dropped the lock guard and we're safe to acquire a new one.
// We atomically swap in a `true` so, if two threads are racing to lock, only one succeeds.
while self.locked.swap(true, Ordering::Acquire) {
hint::spin_loop();
}
SpinLockGuard { lock: self }
}
pub fn into_inner(this: Self) -> T {
this.data.into_inner()
}
}