Skip to main content

conc_util/sync/
spinlock.rs

1use core::{
2    cell::UnsafeCell,
3    ops::{Deref, DerefMut},
4    sync::atomic::{AtomicBool, Ordering},
5};
6
7#[derive(Debug)]
8pub struct SpinLock<T = ()>(AtomicBool, UnsafeCell<T>);
9
10// SAFETY: UnsafeCell is only accessed when locked atomically.
11unsafe impl Sync for SpinLock {}
12
13impl<T> SpinLock<T> {
14    pub fn new(data: T) -> Self {
15        Self(AtomicBool::new(false), UnsafeCell::new(data))
16    }
17
18    pub fn get(&mut self) -> &mut T {
19        self.1.get_mut()
20    }
21
22    pub fn lock<'a>(&'a self) -> SpinLockScope<'a, T> {
23        while self.0.swap(true, Ordering::AcqRel) {}
24        // SAFETY: spinlock above guarantees unique access
25        let locked = unsafe { self.1.get().as_mut_unchecked() };
26        SpinLockScope(&self.0, locked)
27    }
28}
29
30#[derive(Debug)]
31pub struct SpinLockScope<'a, T>(&'a AtomicBool, &'a mut T);
32
33impl<'a, T> Drop for SpinLockScope<'a, T> {
34    fn drop(&mut self) {
35        self.0.store(false, Ordering::Release);
36    }
37}
38
39impl<'a, T> Deref for SpinLockScope<'a, T> {
40    type Target = T;
41
42    fn deref(&self) -> &Self::Target {
43        self.1
44    }
45}
46
47impl<'a, T> DerefMut for SpinLockScope<'a, T> {
48    fn deref_mut(&mut self) -> &mut Self::Target {
49        self.1
50    }
51}