os/sync/
intr_guard.rs

1use crate::arch::{
2    constant::SSTATUS_SIE,
3    intr::{read_and_disable_interrupts, restore_interrupts},
4};
5use core::ops::Drop;
6
7/// 中断保护器,基于 RAII 实现中断保护。
8/// 在创建时原子地禁用中断并保存之前的状态;
9/// 在销毁时自动恢复之前的中断状态。
10/// 不可重入 (即不能嵌套调用 IntrGuard::new())。
11/// 使用示例:
12/// ```ignore
13/// {
14///     let guard = IntrGuard::new(); // 禁用中断
15///     // 临界区代码
16/// } // 离开作用域,自动恢复中断状态
17/// ```
18pub struct IntrGuard {
19    flags: usize,
20}
21
22impl IntrGuard {
23    /// 原子地禁用中断并返回一个 IntrGuard 实例。
24    /// 该实例在离开作用域时会自动恢复中断状态。
25    pub fn new() -> Self {
26        // SAFETY: 调用者必须确保在创建 IntrGuard 实例时,
27        // 没有其他代码会修改中断状态,从而保证不可重入性。
28        let flags = unsafe { read_and_disable_interrupts() };
29        IntrGuard { flags }
30    }
31
32    /// 检查进入临界区前,中断是否处于启用状态。
33    /// 返回值:中断是否处于启用状态
34    #[allow(dead_code)]
35    pub fn was_enabled(&self) -> bool {
36        self.flags & SSTATUS_SIE != 0
37    }
38}
39
40impl Drop for IntrGuard {
41    /// 当 IntrGuard 离开作用域时,自动恢复中断状态。
42    fn drop(&mut self) {
43        // SAFETY: flags 是在创建 IntrGuard 时保存的,
44        // 因此恢复操作是安全的。
45        unsafe { restore_interrupts(self.flags) };
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    use crate::{arch::intr::*, kassert, println, test_case};
54
55    // 测试 IntrGuard::new() 是否成功禁用中断,并检查 was_enabled
56    test_case!(test_guard_disables_interrupts, {
57        println!("Testing: test_guard_disables_interrupts");
58        unsafe { enable_interrupts() };
59        kassert!(are_interrupts_enabled());
60
61        let guard = IntrGuard::new();
62
63        kassert!(guard.was_enabled());
64
65        kassert!(!are_interrupts_enabled());
66    });
67
68    // 测试 IntrGuard 在离开作用域时是否恢复中断状态
69    test_case!(test_guard_restores_on_drop, {
70        println!("Testing: test_guard_restores_on_drop");
71        let initial_flags: usize = {
72            let flags = unsafe { read_and_disable_interrupts() };
73            unsafe { enable_interrupts() };
74            flags
75        };
76
77        let initial_state = are_interrupts_enabled();
78
79        kassert!(initial_state);
80
81        {
82            let guard = IntrGuard::new();
83            kassert!(!are_interrupts_enabled());
84
85            kassert!(guard.flags & SSTATUS_SIE != 0);
86        }
87
88        kassert!(are_interrupts_enabled());
89
90        unsafe { restore_interrupts(initial_flags) };
91    });
92}