1use core::cell::UnsafeCell;
4use core::ptr::NonNull;
5use core::sync::atomic::AtomicBool;
6use core::sync::atomic::Ordering;
7
8#[proc_macros::fmt]
10pub struct SpinLock {
11 lock: AtomicBool,
12}
13
14#[allow(dead_code)]
15impl SpinLock {
16 pub const fn new() -> Self {
18 SpinLock {
19 lock: AtomicBool::new(false),
20 }
21 }
22
23 pub fn lock(&self) {
25 let lock = &self.lock;
26
27 if lock.load(Ordering::Relaxed) {
28 hal::asm::nop!();
29 }
30
31 loop {
32 if lock
33 .compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Relaxed)
34 .is_ok()
35 {
36 break;
37 }
38 }
39 }
40
41 pub fn try_lock(&self) -> bool {
44 !self.lock.swap(true, Ordering::Acquire)
45 }
46
47 pub unsafe fn unlock(&self) {
54 self.lock.store(false, Ordering::Release)
55 }
56}
57
58#[proc_macros::fmt]
60pub struct SpinLockGuard<'a, T: ?Sized> {
61 lock: &'a SpinLock,
62 value: NonNull<T>,
63 marker: core::marker::PhantomData<&'a mut T>,
64}
65
66impl<T: ?Sized> core::ops::Deref for SpinLockGuard<'_, T> {
67 type Target = T;
68
69 #[inline]
70 fn deref(&self) -> &T {
71 unsafe { self.value.as_ref() }
72 }
73}
74
75impl<T: ?Sized> core::ops::DerefMut for SpinLockGuard<'_, T> {
76 fn deref_mut(&mut self) -> &mut T {
77 unsafe { self.value.as_mut() }
78 }
79}
80
81impl<T: ?Sized> Drop for SpinLockGuard<'_, T> {
82 fn drop(&mut self) {
83 unsafe {
84 self.lock.unlock();
85 }
86 }
87}
88
89pub struct SpinLocked<T> {
91 lock: SpinLock,
92 value: UnsafeCell<T>,
93}
94
95unsafe impl<T> Sync for SpinLocked<T> {}
96
97#[allow(dead_code)]
99impl<T> SpinLocked<T> {
100 pub const fn new(value: T) -> Self {
102 SpinLocked {
103 lock: SpinLock::new(),
104 value: UnsafeCell::new(value),
105 }
106 }
107
108 pub fn lock(&self) -> SpinLockGuard<'_, T> {
110 self.lock.lock();
111 SpinLockGuard {
112 lock: &self.lock,
113 value: unsafe { NonNull::new_unchecked(self.value.get()) },
114 marker: core::marker::PhantomData,
115 }
116 }
117
118 pub fn try_lock(&self) -> Option<SpinLockGuard<'_, T>> {
120 if self.lock.try_lock() {
121 Some(SpinLockGuard {
122 lock: &self.lock,
123 value: unsafe { NonNull::new_unchecked(self.value.get()) },
124 marker: core::marker::PhantomData,
125 })
126 } else {
127 None
128 }
129 }
130}