Add spin lock without disabling local irq

This commit is contained in:
Chuandong Li 2023-07-02 18:18:35 +08:00 committed by Tate, Hongliang Tian
parent e2f3932cb8
commit ba4121cd6a
2 changed files with 72 additions and 11 deletions

View File

@ -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;

View File

@ -21,26 +21,27 @@ impl<T> SpinLock<T> {
}
}
/// 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<T> {
pub fn lock_irq_disabled(&self) -> SpinLockIrqDisabledGuard<T> {
// 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<SpinLockGuard<T>> {
/// Try acquiring the spin lock immedidately with disabling the local IRQs.
pub fn try_lock_irq_disabled(&self) -> Option<SpinLockIrqDisabledGuard<T>> {
// 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<T> SpinLock<T> {
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<T> {
// 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<SpinLockGuard<T>> {
// 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<T: fmt::Debug> fmt::Debug for SpinLock<T> {
unsafe impl<T: Send> Send for SpinLock<T> {}
unsafe impl<T: Send> Sync for SpinLock<T> {}
/// 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<T>,
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<T: Sync> Sync for SpinLockIrqDisabledGuard<'_, T> {}
pub struct SpinLockGuard<'a, T> {
lock: &'a SpinLock<T>,
}
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<T: Sync> Sync for SpinLockGuard<'_, T> {}