Skip to main content

strat9_kernel/sync/
irq.rs

1use crate::arch::x86_64;
2
3/// Preuve typée que les IRQ sont masquées sur le CPU courant.
4///
5/// L'allocateur mémoire consomme ce token pour empêcher à la compilation les
6/// appels depuis des contextes où une interruption pourrait ré-entrer sur le
7/// même verrou et provoquer un deadlock.
8///
9/// Intentionnellement non-`Copy` et non-`Clone` : le token ne doit pas pouvoir
10/// s'échapper du contexte IRQ-off dans lequel il a été créé.
11#[derive(Debug)]
12pub struct IrqDisabledToken(());
13
14impl IrqDisabledToken {
15    /// Vérifie l'état courant des interruptions et retourne la preuve si elles
16    /// sont déjà désactivées.
17    #[inline]
18    pub fn verify() -> Option<Self> {
19        if x86_64::interrupts_enabled() {
20            None
21        } else {
22            Some(Self(()))
23        }
24    }
25
26    /// Construit la preuve sans relire `RFLAGS`.
27    ///
28    /// # Safety
29    ///
30    /// L'appelant doit garantir que les interruptions sont bien désactivées sur
31    /// le CPU courant pendant toute la durée de validité logique du token.
32    #[inline]
33    pub(crate) unsafe fn new_unchecked() -> Self {
34        Self(())
35    }
36}
37
38/// Execute a closure with IRQs disabled, providing an `IrqDisabledToken` as proof.
39///
40/// Saves and disables IRQs before calling `f`, then restores the previous flag state.
41#[inline]
42pub fn with_irqs_disabled<R>(f: impl FnOnce(&IrqDisabledToken) -> R) -> R {
43    let saved = crate::arch::x86_64::save_flags_and_cli();
44    // SAFETY: save_flags_and_cli() has just disabled interrupts on this CPU;
45    // the token is dropped before restore_flags() re-enables them.
46    let token = unsafe { IrqDisabledToken::new_unchecked() };
47    let result = f(&token);
48    crate::arch::x86_64::restore_flags(saved);
49    result
50}