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