1use crate::sync::intr_guard::IntrGuard;
2use core::{
3 hint,
4 sync::atomic::{AtomicBool, Ordering},
5};
6
7#[derive(Debug)]
19pub struct RawSpinLock {
20 lock: AtomicBool,
21}
22
23impl RawSpinLock {
24 pub const fn new() -> Self {
25 RawSpinLock {
26 lock: AtomicBool::new(false),
27 }
28 }
29
30 pub fn lock(&self) -> RawSpinLockGuard<'_> {
34 let guard = IntrGuard::new();
35
36 while self
37 .lock
38 .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
39 .is_err()
40 {
41 hint::spin_loop();
42 }
43
44 RawSpinLockGuard {
45 lock: self,
46 intr_guard: guard,
47 }
48 }
49
50 pub fn try_lock(&self) -> Option<RawSpinLockGuard<'_>> {
55 let guard = IntrGuard::new();
56
57 if self
58 .lock
59 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
60 .is_ok()
61 {
62 Some(RawSpinLockGuard {
63 lock: self,
64 intr_guard: guard,
65 })
66 } else {
67 None
68 }
69 }
70
71 fn unlock(&self) {
73 self.lock.store(false, Ordering::Release);
74 }
75
76 #[cfg(test)]
79 pub fn is_locked(&self) -> bool {
80 self.lock.load(Ordering::Relaxed)
81 }
82}
83
84pub struct RawSpinLockGuard<'a> {
86 lock: &'a RawSpinLock,
87 intr_guard: IntrGuard,
88}
89
90use core::ops::Drop;
91
92impl Drop for RawSpinLockGuard<'_> {
93 fn drop(&mut self) {
97 self.lock.unlock();
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::{
105 arch::intr::{are_interrupts_enabled, read_and_disable_interrupts, restore_interrupts},
106 kassert, test_case,
107 };
108
109 static COUNTER: AtomicBool = AtomicBool::new(false);
111
112 test_case!(test_raw_spin_lock_basic_lock_unlock, {
114 let lock = RawSpinLock::new();
115 kassert!(!lock.is_locked());
116
117 let guard = lock.lock();
118 kassert!(lock.is_locked());
119
120 drop(guard);
122 kassert!(!lock.is_locked());
123 });
124
125 test_case!(test_raw_spin_lock_raii_release, {
127 let lock = RawSpinLock::new();
128
129 {
130 let _guard = lock.lock();
131 kassert!(lock.is_locked());
132 } kassert!(!lock.is_locked());
135 });
136
137 test_case!(test_raw_spin_lock_mutual_exclusion, {
139 let lock = RawSpinLock::new();
140
141 let guard1 = lock.lock();
142 kassert!(lock.is_locked());
143
144 let second_lock_failed;
150
151 drop(guard1);
153
154 let guard2 = lock.lock();
155 if lock.is_locked() {
156 second_lock_failed = false;
158 } else {
159 second_lock_failed = true;
160 }
161
162 kassert!(!second_lock_failed);
163 drop(guard2);
164 });
165
166 test_case!(test_interrupt_disable, {
172 let initial_flags = unsafe { read_and_disable_interrupts() };
174 unsafe { restore_interrupts(initial_flags | (1 << 1)) }; kassert!(are_interrupts_enabled());
176
177 let lock = RawSpinLock::new();
178 let guard = lock.lock();
179
180 kassert!(!are_interrupts_enabled());
182 kassert!(guard.intr_guard.was_enabled());
183
184 drop(guard);
186 kassert!(are_interrupts_enabled());
187
188 unsafe { restore_interrupts(initial_flags) };
190 });
191}