ostd/irq/guard.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
// SPDX-License-Identifier: MPL-2.0
//! The IRQ disabling guard.
use crate::{arch::irq as arch_irq, sync::GuardTransfer, task::atomic_mode::InAtomicMode};
/// Disables all IRQs on the current CPU (i.e., locally).
///
/// This function returns a guard object, which will automatically enable local IRQs again when
/// it is dropped. This function works correctly even when it is called in a _nested_ way.
/// The local IRQs shall only be re-enabled when the most outer guard is dropped.
///
/// This function can play nicely with [`SpinLock`] as the type uses this function internally.
/// One can invoke this function even after acquiring a spin lock. And the reversed order is also ok.
///
/// [`SpinLock`]: crate::sync::SpinLock
///
/// # Example
///
/// ```rust
/// use ostd::irq;
///
/// {
/// let _ = irq::disable_local();
/// todo!("do something when irqs are disabled");
/// }
/// ```
pub fn disable_local() -> DisabledLocalIrqGuard {
DisabledLocalIrqGuard::new()
}
/// A guard for disabled local IRQs.
#[clippy::has_significant_drop]
#[must_use]
#[derive(Debug)]
pub struct DisabledLocalIrqGuard {
was_enabled: bool,
}
impl !Send for DisabledLocalIrqGuard {}
// SAFETY: The guard disables local IRQs, which meets the first
// sufficient condition for atomic mode.
unsafe impl InAtomicMode for DisabledLocalIrqGuard {}
impl DisabledLocalIrqGuard {
fn new() -> Self {
let was_enabled = arch_irq::is_local_enabled();
if was_enabled {
arch_irq::disable_local();
}
Self { was_enabled }
}
}
impl GuardTransfer for DisabledLocalIrqGuard {
fn transfer_to(&mut self) -> Self {
let was_enabled = self.was_enabled;
self.was_enabled = false;
Self { was_enabled }
}
}
impl Drop for DisabledLocalIrqGuard {
fn drop(&mut self) {
if self.was_enabled {
arch_irq::enable_local();
}
}
}