Linux软中断
Linux中的中断主要分成了top-half和bottom-half两个部分来进行整个中断的处理。
top-half和bottom-half主要区别在于前者位于硬中断的处理流程中完成追求执行效率越快越好并利用bottom-half来处理剩余逻辑以尽可能多的处理中断事件,后者则是处理较费时或者阻塞的延迟任务等。
本文主要是针对软中断场景进行学习。
在Linux的软中断中,当前有如下的几种软中断的类型来进行调度执行。
在softirq中,主要有如下的几种类型:
优先级 | 名称 | 主要任务 |
---|---|---|
0 | HI_SOFTIRQ | 处理tasklet_hi任务 |
1 | TIMER_SOFTIRQ | 处理cpu的计时器相关 |
2 | NET_TX_SOFTIRQ | 处理网络设备发送的数据 |
3 | NET_RX_SOFTIRQ | 处理网络设备接受的数据 |
4 | BLOCK_SOFTIRQ | 处理块设备的中断 |
5 | IRQ_POLL_SOFTIRQ | 用于执行IOPOLL的回调函数 |
6 | TASKLET_SOFTIRQ | 用户处理tasklet任务执行 |
7 | SCHED_SOFTIRQ | 用于进程调度相关 |
8 | HRTIMER_SOFTIRQ | |
9 | RCU_SOFTIRQ |
软中断的注册流程
softirq的注册函数如下:
// 注册的action的类型就是一个可执行的函数
struct softirq_action
{
void (*action)(struct softirq_action *);
};
...
// 将软中断的函数直接保存
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
软中断的注册的函数如下:
// tasklet的软中断注册
void __init softirq_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
per_cpu(tasklet_vec, cpu).tail =
&per_cpu(tasklet_vec, cpu).head;
per_cpu(tasklet_hi_vec, cpu).tail =
&per_cpu(tasklet_hi_vec, cpu).head;
}
open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}
// 网络设备的注册的数据接受
static int __init net_dev_init(void)
{
int i, rc = -ENOMEM;
...
if (register_pernet_device(&loopback_net_ops))
goto out;
if (register_pernet_device(&default_device_ops))
goto out;
open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);
rc = cpuhp_setup_state_nocalls(CPUHP_NET_DEV_DEAD, "net/dev:dead",
NULL