Implement WriteIrqDisabled

This commit is contained in:
Ruihan Li
2024-12-03 10:51:11 +08:00
committed by Tate, Hongliang Tian
parent 29659dbc98
commit a260411a2a
7 changed files with 58 additions and 22 deletions

View File

@ -5,13 +5,17 @@ use crate::{
trap::{disable_local, DisabledLocalIrqGuard},
};
/// A guardian that denotes the guard behavior for holding the spin lock.
/// A guardian that denotes the guard behavior for holding a lock.
pub trait Guardian {
/// The guard type.
/// The guard type for holding a spin lock or a write lock.
type Guard: GuardTransfer;
/// The guard type for holding a read lock.
type ReadGuard: GuardTransfer;
/// Creates a new guard.
fn guard() -> Self::Guard;
/// Creates a new read guard.
fn read_guard() -> Self::ReadGuard;
}
/// The Guard can be transferred atomically.
@ -25,21 +29,25 @@ pub trait GuardTransfer {
fn transfer_to(&mut self) -> Self;
}
/// A guardian that disables preemption while holding the spin lock.
/// A guardian that disables preemption while holding a lock.
pub struct PreemptDisabled;
impl Guardian for PreemptDisabled {
type Guard = DisabledPreemptGuard;
type ReadGuard = DisabledPreemptGuard;
fn guard() -> Self::Guard {
disable_preempt()
}
fn read_guard() -> Self::Guard {
disable_preempt()
}
}
/// A guardian that disables IRQs while holding the spin lock.
/// A guardian that disables IRQs while holding a lock.
///
/// This guardian would incur a certain time overhead over
/// [`PreemptDisabled']. So prefer avoiding using this guardian when
/// [`PreemptDisabled`]. So prefer avoiding using this guardian when
/// IRQ handlers are allowed to get executed while holding the
/// lock. For example, if a lock is never used in the interrupt
/// context, then it is ok not to use this guardian in the process context.
@ -47,8 +55,38 @@ pub struct LocalIrqDisabled;
impl Guardian for LocalIrqDisabled {
type Guard = DisabledLocalIrqGuard;
type ReadGuard = DisabledLocalIrqGuard;
fn guard() -> Self::Guard {
disable_local()
}
fn read_guard() -> Self::Guard {
disable_local()
}
}
/// A guardian that disables IRQs while holding a write lock.
///
/// This guardian should only be used for a [`RwLock`]. Using it with a [`SpinLock`] will behave in
/// the same way as using [`LocalIrqDisabled`].
///
/// When using this guardian with a [`RwLock`], holding the read lock will only disable preemption,
/// but holding a write lock will disable local IRQs. The user must ensure that the IRQ handlers
/// never take the write lock, so we can take the read lock without disabling IRQs, but we are
/// still free of deadlock even if the IRQ handlers are triggered in the middle.
///
/// [`RwLock`]: super::RwLock
/// [`SpinLock`]: super::SpinLock
pub struct WriteIrqDisabled;
impl Guardian for WriteIrqDisabled {
type Guard = DisabledLocalIrqGuard;
type ReadGuard = DisabledPreemptGuard;
fn guard() -> Self::Guard {
disable_local()
}
fn read_guard() -> Self::ReadGuard {
disable_preempt()
}
}

View File

@ -15,7 +15,7 @@ mod wait;
// pub use self::rcu::{pass_quiescent_state, OwnerPtr, Rcu, RcuReadGuard, RcuReclaimer};
pub(crate) use self::guard::GuardTransfer;
pub use self::{
guard::{LocalIrqDisabled, PreemptDisabled},
guard::{LocalIrqDisabled, PreemptDisabled, WriteIrqDisabled},
mutex::{ArcMutexGuard, Mutex, MutexGuard},
rwlock::{
ArcRwLockReadGuard, ArcRwLockUpgradeableGuard, ArcRwLockWriteGuard, RwLock,

View File

@ -230,7 +230,7 @@ impl<T: ?Sized, G: Guardian> RwLock<T, G> {
///
/// This function will never spin-wait and will return immediately.
pub fn try_read(&self) -> Option<RwLockReadGuard<T, G>> {
let guard = G::guard();
let guard = G::read_guard();
let lock = self.lock.fetch_add(READER, Acquire);
if lock & (WRITER | MAX_READER | BEING_UPGRADED) == 0 {
Some(RwLockReadGuard { inner: self, guard })
@ -247,7 +247,7 @@ impl<T: ?Sized, G: Guardian> RwLock<T, G> {
///
/// [`try_read`]: Self::try_read
pub fn try_read_arc(self: &Arc<Self>) -> Option<ArcRwLockReadGuard<T, G>> {
let guard = G::guard();
let guard = G::read_guard();
let lock = self.lock.fetch_add(READER, Acquire);
if lock & (WRITER | MAX_READER | BEING_UPGRADED) == 0 {
Some(ArcRwLockReadGuard {
@ -375,7 +375,7 @@ unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G:
#[clippy::has_significant_drop]
#[must_use]
pub struct RwLockReadGuard_<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> {
guard: G::Guard,
guard: G::ReadGuard,
inner: R,
}