xref: /DragonOS/docs/kernel/core_api/softirq.md (revision 8fd71f277271ae68e648f290c67f187b030feae0)
1*8fd71f27Shoumkh# 软中断
2*8fd71f27Shoumkh
3*8fd71f27Shoumkh  软件中断,也可以被称为中断的下半部,用于延迟处理硬中断(中断上半部)未完成的工作。将中断分为两个阶段可以有效解决中断处理时间过长和中断丢失的问题。
4*8fd71f27Shoumkh
5*8fd71f27Shoumkh## 1. 设计思路
6*8fd71f27Shoumkh
7*8fd71f27Shoumkh  每个cpu都有自己的pending,软中断是“哪个cpu发起,就哪个cpu执行”,每个cpu的pending不共享。同一个软中断向量可以在多核上同时运行。
8*8fd71f27Shoumkh
9*8fd71f27Shoumkh  当我们需要注册一个新的软中断时,需要为软中断处理程序实现`SoftirqVec`特征,然后调用`register_softirq`函数,将软中断处理程序注册到软中断机制内。
10*8fd71f27Shoumkh
11*8fd71f27Shoumkh  请注意,由于软中断的可重入、可并发性,所以软中断处理程序需要自己保证线程安全。
12*8fd71f27Shoumkh
13*8fd71f27Shoumkh## 2. 软中断向量号
14*8fd71f27Shoumkh
15*8fd71f27Shoumkh```rust
16*8fd71f27Shoumkhpub enum SoftirqNumber {
17*8fd71f27Shoumkh    /// 时钟软中断信号
18*8fd71f27Shoumkh    TIMER = 0,
19*8fd71f27Shoumkh    /// 帧缓冲区刷新软中断
20*8fd71f27Shoumkh    VideoRefresh = 1,
21*8fd71f27Shoumkh}
22*8fd71f27Shoumkh```
23*8fd71f27Shoumkh
24*8fd71f27Shoumkh## 3. 软中断API
25*8fd71f27Shoumkh
26*8fd71f27Shoumkh### 3.1. SoftirqVec特征
27*8fd71f27Shoumkh
28*8fd71f27Shoumkh```rust
29*8fd71f27Shoumkhpub trait SoftirqVec: Send + Sync + Debug {
30*8fd71f27Shoumkh    fn run(&self);
31*8fd71f27Shoumkh}
32*8fd71f27Shoumkh```
33*8fd71f27Shoumkh
34*8fd71f27Shoumkh  软中断处理程序需要实现的特征,需要实现`run`函数,用于处理软中断。当软中断被执行时,会调用`run`函数。
35*8fd71f27Shoumkh
36*8fd71f27Shoumkh### 3.2. Softirq的API
37*8fd71f27Shoumkh
38*8fd71f27Shoumkh#### 3.2.1. 注册软中断向量
39*8fd71f27Shoumkh```rust
40*8fd71f27Shoumkhpub fn register_softirq(&self,
41*8fd71f27Shoumkh        softirq_num: SoftirqNumber,
42*8fd71f27Shoumkh        handler: Arc<dyn SoftirqVec>,
43*8fd71f27Shoumkh    ) -> Result<i32, SystemError>
44*8fd71f27Shoumkh```
45*8fd71f27Shoumkh
46*8fd71f27Shoumkh- 参数:
47*8fd71f27Shoumkh
48*8fd71f27Shoumkh  - softirq_num:中断向量号
49*8fd71f27Shoumkh
50*8fd71f27Shoumkh  - hanlder:中断函数对应的结构体,需要指向实现了`SoftirqVec`特征的结构体变量
51*8fd71f27Shoumkh
52*8fd71f27Shoumkh- 返回:
53*8fd71f27Shoumkh
54*8fd71f27Shoumkh  - Ok(i32):0
55*8fd71f27Shoumkh
56*8fd71f27Shoumkh  - Err(SystemError):错误码
57*8fd71f27Shoumkh
58*8fd71f27Shoumkh#### 3.2.2. 解注册软中断向量
59*8fd71f27Shoumkh
60*8fd71f27Shoumkh```rust
61*8fd71f27Shoumkhpub fn unregister_softirq(&self, softirq_num: SoftirqNumber)
62*8fd71f27Shoumkh```
63*8fd71f27Shoumkh
64*8fd71f27Shoumkh- 参数:
65*8fd71f27Shoumkh
66*8fd71f27Shoumkh  - softirq_num:中断向量号
67*8fd71f27Shoumkh
68*8fd71f27Shoumkh
69*8fd71f27Shoumkh#### 3.2.3. 软中断执行
70*8fd71f27Shoumkh
71*8fd71f27Shoumkh```rust
72*8fd71f27Shoumkhpub fn do_softirq(&self)
73*8fd71f27Shoumkh```
74*8fd71f27Shoumkh
75*8fd71f27Shoumkh- 作用:执行软中断函数(**只在硬中断执行后调用**)
76*8fd71f27Shoumkh
77*8fd71f27Shoumkh#### 3.2.4. 清除软中断的pending标志
78*8fd71f27Shoumkh
79*8fd71f27Shoumkh```rust
80*8fd71f27Shoumkhpub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber)
81*8fd71f27Shoumkh```
82*8fd71f27Shoumkh
83*8fd71f27Shoumkh- 作用:清除当前CPU上,指定软中断的pending标志。请注意,这个函数是unsafe的,因为它会直接修改pending标志,而没有加锁。
84*8fd71f27Shoumkh
85*8fd71f27Shoumkh- 参数:
86*8fd71f27Shoumkh
87*8fd71f27Shoumkh  - softirq_num:中断向量号
88*8fd71f27Shoumkh
89*8fd71f27Shoumkh#### 3.2.5. 标志软中断需要执行
90*8fd71f27Shoumkh
91*8fd71f27Shoumkh```rust
92*8fd71f27Shoumkhpub fn raise_softirq(&self, softirq_num: SoftirqNumber)
93*8fd71f27Shoumkh```
94*8fd71f27Shoumkh
95*8fd71f27Shoumkh- 作用:标志当前CPU上,指定的软中断需要执行
96*8fd71f27Shoumkh
97*8fd71f27Shoumkh- 参数:
98*8fd71f27Shoumkh
99*8fd71f27Shoumkh  - softirq_num:中断向量号
100*8fd71f27Shoumkh
101*8fd71f27Shoumkh### 3.3. 使用实例
102*8fd71f27Shoumkh
103*8fd71f27Shoumkh```rust
104*8fd71f27Shoumkh#[derive(Debug)]
105*8fd71f27Shoumkh/// SoftirqExample中断结构体
106*8fd71f27Shoumkhpub struct SoftirqExample {
107*8fd71f27Shoumkh    running: AtomicBool,
108*8fd71f27Shoumkh}
109*8fd71f27Shoumkh/// SoftirqExample中断需要处理的逻辑
110*8fd71f27Shoumkhfn softirq_example_func() {
111*8fd71f27Shoumkh    println!("addressed SoftirqExample");
112*8fd71f27Shoumkh}
113*8fd71f27Shoumkhimpl SoftirqVec for SoftirqExample {
114*8fd71f27Shoumkh    fn run(&self) {
115*8fd71f27Shoumkh        if self.set_run() == false {
116*8fd71f27Shoumkh            return;
117*8fd71f27Shoumkh        }
118*8fd71f27Shoumkh
119*8fd71f27Shoumkh        softirq_example_func();
120*8fd71f27Shoumkh
121*8fd71f27Shoumkh        self.clear_run();
122*8fd71f27Shoumkh    }
123*8fd71f27Shoumkh}
124*8fd71f27Shoumkhimpl SoftirqExample {
125*8fd71f27Shoumkh    pub fn new() -> SoftirqExample {
126*8fd71f27Shoumkh        SoftirqExample {
127*8fd71f27Shoumkh            running: AtomicBool::new(false),
128*8fd71f27Shoumkh        }
129*8fd71f27Shoumkh    }
130*8fd71f27Shoumkh
131*8fd71f27Shoumkh    fn set_run(&self) -> bool {
132*8fd71f27Shoumkh        let x = self
133*8fd71f27Shoumkh            .running
134*8fd71f27Shoumkh            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed);
135*8fd71f27Shoumkh        if x.is_ok() {
136*8fd71f27Shoumkh            return true;
137*8fd71f27Shoumkh        } else {
138*8fd71f27Shoumkh            return false;
139*8fd71f27Shoumkh        }
140*8fd71f27Shoumkh    }
141*8fd71f27Shoumkh
142*8fd71f27Shoumkh    fn clear_run(&self) {
143*8fd71f27Shoumkh        self.running.store(false, Ordering::Release);
144*8fd71f27Shoumkh    }
145*8fd71f27Shoumkh}
146*8fd71f27Shoumkhfn main() {
147*8fd71f27Shoumkh    let softirq_example = Arc::new(SoftirqExample::new());
148*8fd71f27Shoumkh    let softirq_num = 2;
149*8fd71f27Shoumkh    // 注册SoftirqExample中断
150*8fd71f27Shoumkh    softirq_vectors()
151*8fd71f27Shoumkh        .register_softirq(SoftirqNumber::from(softirq_num as u64), softirq_example)
152*8fd71f27Shoumkh        .expect("failed to register SoftirqExample");
153*8fd71f27Shoumkh
154*8fd71f27Shoumkh    // 标志SoftirqExample中断需要执行
155*8fd71f27Shoumkh    softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
156*8fd71f27Shoumkh
157*8fd71f27Shoumkh    // 标志SoftirqExample中断不需要执行
158*8fd71f27Shoumkh    softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
159*8fd71f27Shoumkh
160*8fd71f27Shoumkh    // 解注册SoftirqExample中断
161*8fd71f27Shoumkh    softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
162*8fd71f27Shoumkh}
163*8fd71f27Shoumkh```
164*8fd71f27Shoumkh
165*8fd71f27Shoumkh### 3.4. 为C提供的接口
166*8fd71f27Shoumkh
167*8fd71f27Shoumkh```c
168*8fd71f27Shoumkhextern void rs_softirq_init();
169*8fd71f27Shoumkhextern void rs_raise_softirq(uint32_t sirq_num);
170*8fd71f27Shoumkhextern void rs_unregister_softirq(uint32_t sirq_num);
171*8fd71f27Shoumkhextern void rs_do_softirq();
172*8fd71f27Shoumkhextern void rs_clear_softirq_pending(uint32_t softirq_num);
173*8fd71f27Shoumkh```
174