sparreal_kernel/os/sync/
spinlock.rs1use core::cell::UnsafeCell;
7use core::ops::{Deref, DerefMut};
8use core::sync::atomic::{AtomicBool, Ordering};
9
10use crate::os::irq::NoIrqGuard;
11
12pub struct IrqRawSpinlock {
17 locked: AtomicBool,
18}
19
20impl IrqRawSpinlock {
21 #[inline]
23 pub const fn new() -> Self {
24 Self {
25 locked: AtomicBool::new(false),
26 }
27 }
28}
29
30impl Default for IrqRawSpinlock {
31 #[inline]
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl IrqRawSpinlock {
38 #[inline]
43 pub fn lock(&self) {
44 let mut spin_count = 0;
46
47 while self
48 .locked
49 .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
50 .is_err()
51 {
52 core::hint::spin_loop();
54
55 spin_count = (spin_count + 1) & 0xFFF;
57 if spin_count == 0 {
58 core::hint::spin_loop();
60 }
61 }
62 }
63
64 #[inline]
73 pub fn try_lock(&self) -> bool {
74 self.locked
76 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
77 .is_ok()
78 }
79
80 #[inline]
88 pub unsafe fn unlock(&self) {
89 self.locked.store(false, Ordering::Release);
90 }
91
92 #[inline]
94 pub fn is_locked(&self) -> bool {
95 self.locked.load(Ordering::Acquire)
96 }
97}
98
99pub struct IrqSpinlock<T> {
103 raw: IrqRawSpinlock,
104 data: UnsafeCell<T>,
105 }
107
108unsafe impl<T: Send> Send for IrqSpinlock<T> {}
110
111unsafe impl<T: Send> Sync for IrqSpinlock<T> {}
113
114pub struct IrqMutexGuard<'a, T> {
118 lock: &'a IrqSpinlock<T>,
119 _irq_guard: NoIrqGuard, }
121
122impl<T> IrqSpinlock<T> {
123 #[inline]
141 pub const fn new(data: T) -> Self {
142 Self {
143 raw: IrqRawSpinlock::new(),
144 data: UnsafeCell::new(data),
145 }
146 }
147
148 #[inline]
150 pub const fn empty() -> IrqSpinlock<()> {
151 IrqSpinlock::new(())
152 }
153
154 #[inline]
169 pub fn lock(&self) -> IrqMutexGuard<'_, T> {
170 for _ in 0..100 {
171 if let Some(guard) = self.try_lock() {
172 return guard;
173 }
174 }
175 panic!("IrqSpinlock lock timeout");
176 }
177
178 #[inline]
188 pub fn try_lock(&self) -> Option<IrqMutexGuard<'_, T>> {
189 let irq_guard = NoIrqGuard::new();
190 if self.raw.try_lock() {
191 Some(IrqMutexGuard::new(self, irq_guard))
192 } else {
193 None
194 }
195 }
196
197 #[inline]
204 pub fn is_locked(&self) -> bool {
205 self.raw.is_locked()
206 }
207
208 #[inline]
214 pub unsafe fn get(&self) -> *mut T {
215 self.data.get()
216 }
217
218 #[inline]
224 pub unsafe fn get_mut(&mut self) -> &mut T {
225 unsafe { &mut *self.data.get() }
226 }
227
228 #[inline]
234 pub fn into_inner(self) -> T {
235 self.data.into_inner()
236 }
237
238 #[inline]
247 pub unsafe fn lock_raw(&self) -> &IrqRawSpinlock {
248 &self.raw
249 }
250}
251
252impl<'a, T> IrqMutexGuard<'a, T> {
253 fn new(lock: &'a IrqSpinlock<T>, irq_guard: NoIrqGuard) -> Self {
254 Self {
255 lock,
256 _irq_guard: irq_guard,
257 }
258 }
259}
260
261impl<T> Drop for IrqMutexGuard<'_, T> {
262 #[inline]
263 fn drop(&mut self) {
264 unsafe {
265 self.lock.raw.unlock();
266 }
267 }
268}
269
270impl<T> Deref for IrqMutexGuard<'_, T> {
271 type Target = T;
272
273 #[inline]
274 fn deref(&self) -> &Self::Target {
275 unsafe { &*self.lock.data.get() }
276 }
277}
278
279impl<T> DerefMut for IrqMutexGuard<'_, T> {
280 #[inline]
281 fn deref_mut(&mut self) -> &mut Self::Target {
282 unsafe { &mut *self.lock.data.get() }
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289 use crate::alloc::string::String;
290
291 #[test]
292 fn test_irq_raw_spinlock_creation() {
293 let spinlock = IrqRawSpinlock::new();
294 assert!(!spinlock.is_locked());
295 }
296
297 #[test]
298 fn test_irq_raw_spinlock_default() {
299 let spinlock = IrqRawSpinlock::default();
300 assert!(!spinlock.is_locked());
301 }
302
303 #[test]
304 fn test_irq_raw_spinlock_try_lock() {
305 let spinlock = IrqRawSpinlock::new();
306
307 assert!(spinlock.try_lock());
309 assert!(spinlock.is_locked());
310
311 assert!(!spinlock.try_lock());
313
314 unsafe {
316 spinlock.unlock();
317 }
318 assert!(!spinlock.is_locked());
319
320 assert!(spinlock.try_lock());
322 unsafe {
323 spinlock.unlock();
324 }
325 }
326
327 #[test]
328 fn test_irq_spinlock_creation() {
329 let lock = IrqSpinlock::new(42);
330 assert!(!lock.is_locked());
331
332 let value = lock.into_inner();
334 assert_eq!(value, 42);
335 }
336
337 #[test]
338 fn test_irq_spinlock_empty() {
339 let lock: IrqSpinlock<()> = IrqSpinlock::<()>::empty();
340 assert!(!lock.is_locked());
341
342 let value: () = lock.into_inner();
343 assert_eq!(value, ());
344 }
345
346 #[test]
347 fn test_irq_spinlock_try_lock() {
348 let lock = IrqSpinlock::new(42);
349
350 {
352 let guard = lock.try_lock().unwrap();
353 assert_eq!(*guard, 42);
354 assert!(lock.is_locked());
355 } assert!(!lock.is_locked());
358
359 {
361 let guard = lock.try_lock().unwrap();
362 assert_eq!(*guard, 42);
363 }
364 }
365
366 #[test]
367 fn test_irq_spinlock_try_lock_failure() {
368 let lock = IrqSpinlock::new(42);
369
370 let guard1 = lock.try_lock().unwrap();
372 assert!(lock.is_locked());
373
374 let guard2 = lock.try_lock();
376 assert!(guard2.is_none());
377
378 drop(guard1);
380 assert!(!lock.is_locked());
381 }
382
383 #[test]
384 fn test_irq_spinlock_lock_and_modify() {
385 let lock = IrqSpinlock::new(0);
386
387 {
388 let mut guard = lock.lock();
389 *guard = 100;
390 assert_eq!(*guard, 100);
391 } assert!(!lock.is_locked());
394
395 let guard = lock.lock();
397 assert_eq!(*guard, 100);
398 }
399
400 #[test]
401 fn test_multiple_types() {
402 let string_lock = IrqSpinlock::new(String::from("hello"));
404 {
405 let mut guard = string_lock.lock();
406 guard.push_str(" world");
407 assert_eq!(guard.as_str(), "hello world");
408 }
409
410 let array_lock = IrqSpinlock::new([1, 2, 3]);
411 {
412 let guard = array_lock.lock();
413 assert_eq!(*guard, [1, 2, 3]);
414 }
415
416 let struct_lock = IrqSpinlock::new((42, "test"));
417 {
418 let guard = struct_lock.lock();
419 assert_eq!(guard.0, 42);
420 assert_eq!(guard.1, "test");
421 }
422 }
423}