软件中断,也可以被称为中断的下半部,用于延迟处理硬中断(中断上半部)未完成的工作。将中断分为两个阶段可以有效解决中断处理时间过长和中断丢失的问题。
每个cpu都有自己的pending,软中断是“哪个cpu发起,就哪个cpu执行”,每个cpu的pending不共享。同一个软中断向量可以在多核上同时运行。
当我们需要注册一个新的软中断时,需要为软中断处理程序实现SoftirqVec
特征,然后调用register_softirq
函数,将软中断处理程序注册到软中断机制内。
请注意,由于软中断的可重入、可并发性,所以软中断处理程序需要自己保证线程安全。
pub enum SoftirqNumber {
/// 时钟软中断信号
TIMER = 0,
/// 帧缓冲区刷新软中断
VideoRefresh = 1,
}
pub trait SoftirqVec: Send + Sync + Debug {
fn run(&self);
}
软中断处理程序需要实现的特征,需要实现run
函数,用于处理软中断。当软中断被执行时,会调用run
函数。
pub fn register_softirq(&self,
softirq_num: SoftirqNumber,
handler: Arc<dyn SoftirqVec>,
) -> Result<i32, SystemError>
参数:
softirq_num:中断向量号
hanlder:中断函数对应的结构体,需要指向实现了SoftirqVec
特征的结构体变量
返回:
Ok(i32):0
Err(SystemError):错误码
pub fn unregister_softirq(&self, softirq_num: SoftirqNumber)
参数:
pub fn do_softirq(&self)
pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber)
作用:清除当前CPU上,指定软中断的pending标志。请注意,这个函数是unsafe的,因为它会直接修改pending标志,而没有加锁。
参数:
pub fn raise_softirq(&self, softirq_num: SoftirqNumber)
作用:标志当前CPU上,指定的软中断需要执行
参数:
#[derive(Debug)]
/// SoftirqExample中断结构体
pub struct SoftirqExample {
running: AtomicBool,
}
/// SoftirqExample中断需要处理的逻辑
fn softirq_example_func() {
println!("addressed SoftirqExample");
}
impl SoftirqVec for SoftirqExample {
fn run(&self) {
if self.set_run() == false {
return;
}
softirq_example_func();
self.clear_run();
}
}
impl SoftirqExample {
pub fn new() -> SoftirqExample {
SoftirqExample {
running: AtomicBool::new(false),
}
}
fn set_run(&self) -> bool {
let x = self
.running
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed);
if x.is_ok() {
return true;
} else {
return false;
}
}
fn clear_run(&self) {
self.running.store(false, Ordering::Release);
}
}
fn main() {
let softirq_example = Arc::new(SoftirqExample::new());
let softirq_num = 2;
// 注册SoftirqExample中断
softirq_vectors()
.register_softirq(SoftirqNumber::from(softirq_num as u64), softirq_example)
.expect("failed to register SoftirqExample");
// 标志SoftirqExample中断需要执行
softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
// 标志SoftirqExample中断不需要执行
softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
// 解注册SoftirqExample中断
softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
}