Skip to main content

ostd/irq/
guard.rs

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