mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-17 02:26:46 +00:00
Add spin lock without disabling local irq
This commit is contained in:
parent
e2f3932cb8
commit
ba4121cd6a
@ -7,5 +7,5 @@ mod wait;
|
|||||||
pub use self::atomic_bits::AtomicBits;
|
pub use self::atomic_bits::AtomicBits;
|
||||||
pub use self::mutex::{Mutex, MutexGuard};
|
pub use self::mutex::{Mutex, MutexGuard};
|
||||||
pub use self::rcu::{pass_quiescent_state, OwnerPtr, Rcu, RcuReadGuard, RcuReclaimer};
|
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;
|
pub use self::wait::WaitQueue;
|
||||||
|
@ -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.
|
/// This method runs in a busy loop until the lock can be acquired.
|
||||||
/// After acquiring the spin lock, all interrupts are disabled.
|
/// 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
|
// FIXME: add disable_preemption
|
||||||
let guard = disable_local();
|
let guard = disable_local();
|
||||||
self.acquire_lock();
|
self.acquire_lock();
|
||||||
SpinLockGuard {
|
SpinLockIrqDisabledGuard {
|
||||||
lock: &self,
|
lock: &self,
|
||||||
irq_guard: guard,
|
irq_guard: guard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try Acquire the spin lock immedidately.
|
/// Try acquiring the spin lock immedidately with disabling the local IRQs.
|
||||||
pub fn try_lock(&self) -> Option<SpinLockGuard<T>> {
|
pub fn try_lock_irq_disabled(&self) -> Option<SpinLockIrqDisabledGuard<T>> {
|
||||||
// FIXME: add disable_preemption
|
// FIXME: add disable_preemption
|
||||||
let irq_guard = disable_local();
|
let irq_guard = disable_local();
|
||||||
if self.try_acquire_lock() {
|
if self.try_acquire_lock() {
|
||||||
let lock_guard = SpinLockGuard {
|
let lock_guard = SpinLockIrqDisabledGuard {
|
||||||
lock: &self,
|
lock: &self,
|
||||||
irq_guard,
|
irq_guard,
|
||||||
};
|
};
|
||||||
@ -49,6 +50,30 @@ impl<T> SpinLock<T> {
|
|||||||
return None;
|
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
|
/// Access the spin lock, otherwise busy waiting
|
||||||
fn acquire_lock(&self) {
|
fn acquire_lock(&self) {
|
||||||
while !self.try_acquire_lock() {
|
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> Send for SpinLock<T> {}
|
||||||
unsafe impl<T: Send> Sync for SpinLock<T> {}
|
unsafe impl<T: Send> Sync for SpinLock<T> {}
|
||||||
|
|
||||||
/// The guard of a spin lock.
|
/// The guard of a spin lock that disables the local IRQs.
|
||||||
pub struct SpinLockGuard<'a, T> {
|
pub struct SpinLockIrqDisabledGuard<'a, T> {
|
||||||
lock: &'a SpinLock<T>,
|
lock: &'a SpinLock<T>,
|
||||||
irq_guard: DisabledLocalIrqGuard,
|
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> {
|
impl<'a, T> Deref for SpinLockGuard<'a, T> {
|
||||||
type Target = 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> {}
|
impl<'a, T> !Send for SpinLockGuard<'a, T> {}
|
||||||
|
|
||||||
// Safety. SpinLockGuard can be shared between tasks/threads in same CPU.
|
// Safety. `SpinLockGuard` can be shared between tasks/threads in same CPU.
|
||||||
// As SpinLock disables interrupts to prevent race conditions caused by interrupts.
|
// As `lock()` is only called when there are no race conditions caused by interrupts.
|
||||||
unsafe impl<T: Sync> Sync for SpinLockGuard<'_, T> {}
|
unsafe impl<T: Sync> Sync for SpinLockGuard<'_, T> {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user