moto_rt/
spinlock.rs

1/// A minimalistic SpinLock.
2//
3// A slightly modified version of
4// https://github.com/m-ou-se/rust-atomics-and-locks/blob/main/src/ch4_spin_lock/s3_guard.rs
5//
6// which has this LICENCE:
7//
8// You may use all code in this repository for any purpose.
9//
10// Attribution is appreciated, but not required.
11// An attribution usually includes the book title, author,
12// publisher, and ISBN. For example: "Rust Atomics and
13// Locks by Mara Bos (O’Reilly). Copyright 2023 Mara Bos,
14// 978-1-098-11944-7."
15//
16use core::cell::UnsafeCell;
17use core::ops::{Deref, DerefMut};
18use core::sync::atomic::AtomicBool;
19use core::sync::atomic::Ordering::{AcqRel, Relaxed, Release};
20
21#[derive(Default)]
22pub struct SpinLock<T> {
23    locked: AtomicBool,
24    value: UnsafeCell<T>,
25}
26
27unsafe impl<T> Sync for SpinLock<T> where T: Send {}
28
29pub struct Guard<'a, T> {
30    lock: &'a SpinLock<T>,
31}
32
33unsafe impl<T> Sync for Guard<'_, T> where T: Sync {}
34
35impl<T> SpinLock<T> {
36    pub const fn new(value: T) -> Self {
37        Self {
38            locked: AtomicBool::new(false),
39            value: UnsafeCell::new(value),
40        }
41    }
42
43    #[inline]
44    pub fn lock(&self) -> Guard<'_, T> {
45        loop {
46            // Try to acquire the lock.
47            if !self.locked.swap(true, AcqRel) {
48                break; // Acquired the lock
49            }
50
51            // Spin while the lock is already locked.
52            while self.locked.load(Relaxed) {
53                core::hint::spin_loop();
54            }
55        }
56
57        Guard { lock: self }
58    }
59}
60
61impl<T> Deref for Guard<'_, T> {
62    type Target = T;
63    #[inline]
64    fn deref(&self) -> &T {
65        // Safety: The very existence of this Guard
66        // guarantees we've exclusively locked the lock.
67        unsafe { &*self.lock.value.get() }
68    }
69}
70
71impl<T> DerefMut for Guard<'_, T> {
72    #[inline]
73    fn deref_mut(&mut self) -> &mut T {
74        // Safety: The very existence of this Guard
75        // guarantees we've exclusively locked the lock.
76        unsafe { &mut *self.lock.value.get() }
77    }
78}
79
80impl<T> Drop for Guard<'_, T> {
81    #[inline]
82    fn drop(&mut self) {
83        self.lock.locked.store(false, Release);
84    }
85}