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