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