diff --git a/framework/jinux-frame/src/sync/mod.rs b/framework/jinux-frame/src/sync/mod.rs index 9a416987b..7fc175f78 100644 --- a/framework/jinux-frame/src/sync/mod.rs +++ b/framework/jinux-frame/src/sync/mod.rs @@ -7,5 +7,5 @@ mod wait; pub use self::atomic_bits::AtomicBits; pub use self::mutex::{Mutex, MutexGuard}; pub use self::rcu::{pass_quiescent_state, OwnerPtr, Rcu, RcuReadGuard, RcuReclaimer}; -pub use self::spin::{SpinLock, SpinLockGuard}; +pub use self::spin::{SpinLock, SpinLockGuard, SpinLockIrqDisabledGuard}; pub use self::wait::WaitQueue; diff --git a/framework/jinux-frame/src/sync/spin.rs b/framework/jinux-frame/src/sync/spin.rs index 17b576146..04da13ee9 100644 --- a/framework/jinux-frame/src/sync/spin.rs +++ b/framework/jinux-frame/src/sync/spin.rs @@ -21,26 +21,27 @@ impl SpinLock { } } - /// Acquire the spin lock. + /// Acquire the spin lock with disabling the local IRQs. This is the most secure + /// locking way. /// /// This method runs in a busy loop until the lock can be acquired. /// After acquiring the spin lock, all interrupts are disabled. - pub fn lock(&self) -> SpinLockGuard { + pub fn lock_irq_disabled(&self) -> SpinLockIrqDisabledGuard { // FIXME: add disable_preemption let guard = disable_local(); self.acquire_lock(); - SpinLockGuard { + SpinLockIrqDisabledGuard { lock: &self, irq_guard: guard, } } - /// Try Acquire the spin lock immedidately. - pub fn try_lock(&self) -> Option> { + /// Try acquiring the spin lock immedidately with disabling the local IRQs. + pub fn try_lock_irq_disabled(&self) -> Option> { // FIXME: add disable_preemption let irq_guard = disable_local(); if self.try_acquire_lock() { - let lock_guard = SpinLockGuard { + let lock_guard = SpinLockIrqDisabledGuard { lock: &self, irq_guard, }; @@ -49,6 +50,30 @@ impl SpinLock { return None; } + /// Acquire the spin lock without disabling local IRQs. + /// + /// This method is twice as fast as the `lock_irq_disable` method. + /// So prefer using this method over the `lock_irq_disable` method + /// when IRQ handlers are allowed to get executed while + /// holding this lock. For example, if a lock is never used + /// in the interrupt context, then it is ok to use this method + /// in the process context. + pub fn lock(&self) -> SpinLockGuard { + // FIXME: add disable_preemption + self.acquire_lock(); + SpinLockGuard { lock: &self } + } + + /// Try acquiring the spin lock immedidately without disabling the local IRQs. + pub fn try_lock(&self) -> Option> { + // FIXME: add disable_preemption + if self.try_acquire_lock() { + let lock_guard = SpinLockGuard { lock: &self }; + return Some(lock_guard); + } + return None; + } + /// Access the spin lock, otherwise busy waiting fn acquire_lock(&self) { while !self.try_acquire_lock() { @@ -77,12 +102,48 @@ impl fmt::Debug for SpinLock { unsafe impl Send for SpinLock {} unsafe impl Sync for SpinLock {} -/// The guard of a spin lock. -pub struct SpinLockGuard<'a, T> { +/// The guard of a spin lock that disables the local IRQs. +pub struct SpinLockIrqDisabledGuard<'a, T> { lock: &'a SpinLock, irq_guard: DisabledLocalIrqGuard, } +impl<'a, T> Deref for SpinLockIrqDisabledGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &mut *self.lock.val.get() } + } +} + +impl<'a, T> DerefMut for SpinLockIrqDisabledGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.lock.val.get() } + } +} + +impl<'a, T> Drop for SpinLockIrqDisabledGuard<'a, T> { + fn drop(&mut self) { + self.lock.release_lock(); + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for SpinLockIrqDisabledGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, T> !Send for SpinLockIrqDisabledGuard<'a, T> {} + +// Safety. `SpinLockIrqDisabledGuard` can be shared between tasks/threads in same CPU. +// As `lock_irq_disable()` disables interrupts to prevent race conditions caused by interrupts. +unsafe impl Sync for SpinLockIrqDisabledGuard<'_, T> {} + +pub struct SpinLockGuard<'a, T> { + lock: &'a SpinLock, +} + impl<'a, T> Deref for SpinLockGuard<'a, T> { type Target = T; @@ -111,6 +172,6 @@ impl<'a, T: fmt::Debug> fmt::Debug for SpinLockGuard<'a, T> { impl<'a, T> !Send for SpinLockGuard<'a, T> {} -// Safety. SpinLockGuard can be shared between tasks/threads in same CPU. -// As SpinLock disables interrupts to prevent race conditions caused by interrupts. +// Safety. `SpinLockGuard` can be shared between tasks/threads in same CPU. +// As `lock()` is only called when there are no race conditions caused by interrupts. unsafe impl Sync for SpinLockGuard<'_, T> {}