From 9f9397b8b178e7fa3ff26c4365e3b60915dc8eb5 Mon Sep 17 00:00:00 2001 From: Zhiyao Ma Date: Fri, 23 Aug 2024 17:11:51 -0400 Subject: [PATCH] Refactor interrupt masking. --- src/interrupt/mask.rs | 72 ++++++++++++++++++++++++++++++++++++-- src/sync/held_interrupt.rs | 66 ---------------------------------- src/sync/lock_traits.rs | 10 ++++++ src/sync/mod.rs | 2 -- src/sync/mutex.rs | 4 +-- src/sync/spin_lock.rs | 3 +- 6 files changed, 84 insertions(+), 73 deletions(-) delete mode 100644 src/sync/held_interrupt.rs diff --git a/src/interrupt/mask.rs b/src/interrupt/mask.rs index 7ac84a9..1decad6 100644 --- a/src/interrupt/mask.rs +++ b/src/interrupt/mask.rs @@ -1,5 +1,8 @@ -use crate::config; -use core::sync::atomic::{AtomicUsize, Ordering}; +use crate::{config, sync::Holdable}; +use core::{ + marker::PhantomData, + sync::atomic::{AtomicUsize, Ordering}, +}; /// Representing recursively maskable interrupt(s). Recursive means one can /// `mask_recursive` an already masked interrupt, which will increase the @@ -67,6 +70,25 @@ impl RecursivelyMaskable for AllIrqExceptSvc { pub use core::sync::atomic::{AtomicUsize as __AtomicUsize, Ordering as __Ordering}; pub use paste as __paste; +/// Declare an IRQ to be used with the `IrqSafe` variant of locks, e.g., +/// [`SpinIrqSafe`](crate::sync::SpinIrqSafe), +/// [`SpinSchedIrqSafe`](crate::sync::SpinSchedIrqSafe), +/// [`MutexIrqSafe`](crate::sync::MutexIrqSafe). +/// +/// [`declare_irq`] accepts two arguments as in `declare_irq!($name, $irq)`. +/// The macro expands to produce a type with name `$name` which can be passed +/// to the type construction of `IrqSafe` locks. `$irq` should be an enum +/// variant that implements [`cortex_m::interrupt::InterruptNumber`]. +/// +/// # Example +/// ```rust +/// /// Produce the type `Tim2Irq`. +/// declare_irq!(Tim2Irq, stm32f4xx_hal::pac::Interrupt::TIM2); +/// +/// /// The interrupt `TIM2` will be masked whenever the spin lock is acquired. +/// static TIMER: SpinIrqSafe, Tim2Irq> +/// = SpinIrqSafe::new(None); +/// ``` #[macro_export] macro_rules! declare_irq { ($name:ident, $irq:path) => { @@ -97,3 +119,49 @@ macro_rules! declare_irq { } }; } + +/// Representing interrupt(s) being masked. When the struct is dropped, the +/// masked interrupt(s) will be unmasked if no where else is still masking +/// it. See [`RecursivelyMaskable`] for details. +pub struct HeldInterrupt +where + I: RecursivelyMaskable, +{ + _phantom: PhantomData, +} + +impl Drop for HeldInterrupt +where + I: RecursivelyMaskable, +{ + fn drop(&mut self) { + // Safety: An instance can be created only by calling `hold()` where + // `mask_recursive` would have been called. + unsafe { + I::unmask_recursive(); + } + } +} + +/// The status of some interrupt being masked should not be sent across +/// different tasks. +impl !Send for HeldInterrupt {} + +/// That some interrupts are being masked is a holdable condition. +impl Holdable for I +where + I: RecursivelyMaskable, +{ + type GuardType = HeldInterrupt; + + fn hold() -> HeldInterrupt { + I::mask_recursive(); + HeldInterrupt { + _phantom: PhantomData, + } + } + + unsafe fn force_unhold() { + I::unmask_recursive(); + } +} diff --git a/src/sync/held_interrupt.rs b/src/sync/held_interrupt.rs deleted file mode 100644 index fb88035..0000000 --- a/src/sync/held_interrupt.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::Holdable; -use crate::interrupt::mask::RecursivelyMaskable; -use core::marker::PhantomData; - -/// Representing interrupt(s) being masked. When the struct is dropped, -/// the masked interrupt(s) will be unmasked if no one else is also masking -/// it. See `RecursivelyMaskable` for details. -pub struct HeldInterrupt -where - I: RecursivelyMaskable, -{ - _phantom: PhantomData, -} - -/// Mask the given interrupt(s) and return a guard. -pub fn hold_interrupt() -> HeldInterrupt -where - I: RecursivelyMaskable, -{ - I::mask_recursive(); - HeldInterrupt { - _phantom: PhantomData, - } -} - -impl Drop for HeldInterrupt -where - I: RecursivelyMaskable, -{ - // FIXME: this safe wrapper is not safe. - fn drop(&mut self) { - unsafe { - I::unmask_recursive(); - } - } -} - -/// The status of some interrupt being masked should not be sent across -/// different tasks. -impl !Send for HeldInterrupt {} - -/// Masking interrupts is a holdable condition. -impl Holdable for I -where - I: RecursivelyMaskable, -{ - type GuardType = HeldInterrupt; - - fn hold() -> HeldInterrupt { - hold_interrupt() - } - - unsafe fn force_unhold() { - I::unmask_recursive(); - } -} - -/// Used when no additional condition needs to be held. -impl Holdable for () { - type GuardType = (); - - fn hold() -> () { - () - } - unsafe fn force_unhold() {} -} diff --git a/src/sync/lock_traits.rs b/src/sync/lock_traits.rs index 856420d..bf99d3c 100644 --- a/src/sync/lock_traits.rs +++ b/src/sync/lock_traits.rs @@ -56,3 +56,13 @@ where H0::force_unhold(); } } + +/// Used when no additional condition needs to be held. +impl Holdable for () { + type GuardType = (); + + fn hold() -> () { + () + } + unsafe fn force_unhold() {} +} diff --git a/src/sync/mod.rs b/src/sync/mod.rs index a3e9b2c..17b849d 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -1,6 +1,5 @@ mod channel; mod condvar; -mod held_interrupt; mod imported; mod interruptable; mod lock_traits; @@ -13,7 +12,6 @@ mod wait_queue; pub use channel::*; pub use condvar::*; -pub use held_interrupt::*; pub use imported::*; pub use interruptable::*; pub use lock_traits::*; diff --git a/src/sync/mutex.rs b/src/sync/mutex.rs index a201eb6..bea1d71 100644 --- a/src/sync/mutex.rs +++ b/src/sync/mutex.rs @@ -1,8 +1,8 @@ use super::{ - HeldInterrupt, Holdable, Lockable, SpinGeneric, SpinGenericGuard, SpinSchedSafe, - UnlockableGuard, WaitQueue, + Holdable, Lockable, SpinGeneric, SpinGenericGuard, SpinSchedSafe, UnlockableGuard, WaitQueue, }; use crate::{ + interrupt::mask::HeldInterrupt, schedule::{ current, scheduler::{SchedSuspendGuard, Scheduler}, diff --git a/src/sync/spin_lock.rs b/src/sync/spin_lock.rs index 7e060e6..cea29c7 100644 --- a/src/sync/spin_lock.rs +++ b/src/sync/spin_lock.rs @@ -1,5 +1,6 @@ -use super::{HeldInterrupt, Holdable}; +use super::Holdable; use crate::{ + interrupt::mask::HeldInterrupt, schedule::scheduler::{SchedSuspendGuard, Scheduler}, unrecoverable::Lethal, };