//! Synchronization facilities module use crate::arch::platform::{irq_mask_save, irq_restore}; use core::cell::UnsafeCell; use core::fmt; use core::ops::{Deref, DerefMut}; use core::sync::atomic::{AtomicBool, Ordering}; /// Lock structure ensuring IRQs are disabled when inner value is accessed pub struct IrqSafeSpinLock { value: UnsafeCell, state: AtomicBool, } /// Guard-structure wrapping a reference to value owned by [IrqSafeSpinLock]. /// Restores saved IRQ state when dropped. pub struct IrqSafeSpinLockGuard<'a, T> { lock: &'a IrqSafeSpinLock, irq_state: u64, } impl IrqSafeSpinLock { /// Constructs a new instance of the lock, wrapping `value` #[inline(always)] pub const fn new(value: T) -> Self { Self { value: UnsafeCell::new(value), state: AtomicBool::new(false), } } #[inline(always)] fn try_lock(&self) -> Result { self.state .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed) } #[inline(always)] unsafe fn force_release(&self) { self.state.store(false, Ordering::Release); // cortex_a::asm::sev(); } /// Returns [IrqSafeSpinLockGuard] for this lock #[inline] pub fn lock(&self) -> IrqSafeSpinLockGuard { let irq_state = unsafe { irq_mask_save() }; while self.try_lock().is_err() { // cortex_a::asm::wfe(); } IrqSafeSpinLockGuard { lock: self, irq_state, } } } impl Deref for IrqSafeSpinLockGuard<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { unsafe { &*self.lock.value.get() } } } impl DerefMut for IrqSafeSpinLockGuard<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *self.lock.value.get() } } } impl fmt::Debug for IrqSafeSpinLockGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(unsafe { &*self.lock.value.get() }, f) } } impl Drop for IrqSafeSpinLockGuard<'_, T> { #[inline(always)] fn drop(&mut self) { unsafe { self.lock.force_release(); irq_restore(self.irq_state); } } } unsafe impl Sync for IrqSafeSpinLock {}