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// Required by `InAtomicMode`. See the safety section of its doc comments.
46impl !Sync for DisabledLocalIrqGuard {}
47
48// SAFETY:
49// 1. The guard disables local IRQs;
50// 2. The guard cannot be moved to or used by other tasks.
51unsafe impl InAtomicMode for DisabledLocalIrqGuard {}
52
53impl DisabledLocalIrqGuard {
54 fn new() -> Self {
55 let was_enabled = arch_irq::is_local_enabled();
56 if was_enabled {
57 arch_irq::disable_local();
58 }
59 Self { was_enabled }
60 }
61}
62
63impl GuardTransfer for DisabledLocalIrqGuard {
64 fn transfer_to(&mut self) -> Self {
65 let was_enabled = self.was_enabled;
66 self.was_enabled = false;
67 Self { was_enabled }
68 }
69}
70
71impl Drop for DisabledLocalIrqGuard {
72 fn drop(&mut self) {
73 if self.was_enabled {
74 arch_irq::enable_local();
75 }
76 }
77}