feat: replace NullLock with SpinLock
This commit is contained in:
+37
-16
@@ -1,63 +1,84 @@
|
||||
//! Synchronization facilities module
|
||||
|
||||
use crate::arch::platform::{irq_mask_save, irq_restore};
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::cell::UnsafeCell;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
/// Lock structure ensuring IRQs are disabled when inner value is accessed
|
||||
pub struct IrqSafeNullLock<T: ?Sized> {
|
||||
pub struct IrqSafeSpinLock<T> {
|
||||
value: UnsafeCell<T>,
|
||||
state: AtomicBool
|
||||
}
|
||||
|
||||
/// Guard-structure wrapping a reference to value owned by [IrqSafeNullLock].
|
||||
/// Guard-structure wrapping a reference to value owned by [IrqSafeSpinLock].
|
||||
/// Restores saved IRQ state when dropped.
|
||||
pub struct IrqSafeNullLockGuard<'a, T: ?Sized> {
|
||||
value: &'a mut T,
|
||||
pub struct IrqSafeSpinLockGuard<'a, T> {
|
||||
lock: &'a IrqSafeSpinLock<T>,
|
||||
irq_state: u64,
|
||||
}
|
||||
|
||||
impl<T> IrqSafeNullLock<T> {
|
||||
impl<T> IrqSafeSpinLock<T> {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [IrqSafeNullLockGuard] for this lock
|
||||
#[inline(always)]
|
||||
fn try_lock(&self) -> Result<bool, bool> {
|
||||
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) -> IrqSafeNullLockGuard<T> {
|
||||
pub fn lock(&self) -> IrqSafeSpinLockGuard<T> {
|
||||
let irq_state = unsafe { irq_mask_save() };
|
||||
|
||||
while self.try_lock().is_err() {
|
||||
cortex_a::asm::wfe();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
IrqSafeNullLockGuard {
|
||||
value: &mut *self.value.get(),
|
||||
irq_state: irq_mask_save(),
|
||||
IrqSafeSpinLockGuard {
|
||||
lock: self,
|
||||
irq_state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Deref for IrqSafeNullLockGuard<'_, T> {
|
||||
impl<T> Deref for IrqSafeSpinLockGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.value
|
||||
unsafe { &*self.lock.value.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> DerefMut for IrqSafeNullLockGuard<'_, T> {
|
||||
impl<T> DerefMut for IrqSafeSpinLockGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.value
|
||||
unsafe { &mut *self.lock.value.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Drop for IrqSafeNullLockGuard<'_, T> {
|
||||
impl<T> Drop for IrqSafeSpinLockGuard<'_, T> {
|
||||
#[inline(always)]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.lock.force_release();
|
||||
irq_restore(self.irq_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized> Sync for IrqSafeNullLock<T> {}
|
||||
unsafe impl<T> Sync for IrqSafeSpinLock<T> {}
|
||||
|
||||
Reference in New Issue
Block a user