下半部与推后执行的工作
中断处理程序异步执行,需要快速地执行硬件与操作系统的操作,避免其它中断停止太久,因此中断处理程序不能阻塞。
下半部
上半部只能通过中断处理程序实现,而下半部则提供了多种实现机制——软中断、tasklet、工作队列。
内核定时器,这个机制用来将工作推后执行,推后到某个明确的时间段之后执行。
软中断
软中断是一组静态定义的下半部接口,有32个。
1 | struct softirq_action { |
1 | static struct softirq_action softirq_vec[NR_SOFTIRQS]; |
- 软中断处理程序
1 | void sofrirq_handler(struct softirq_action *) |
之所以传递一个指针而不是一个数值,是因为防止后面加上新的域时,无需对处理程序进行改动;
- 执行软中断
一个注册的软中断会在中断处理程序返回前标记了之后才能被执行,会在标记之后一定时间内执行。
在中断处理程序中触发软中断是比较常见的。软中断会在do_softirq()中遍历所有软中断,进行调用。
tasklet
tasklet是使用软中断实现的一种下半部机制,接口更加简单。
tasklet的实现
tasklet有两种软中断代表:HI_SOFTIRQ和TASKLET_SOFTIRQ。
- tasklet结构体
1 | struct tasklet_struct{ |
- 调度tasklet
已经调度的tasklet相当于被触发的软中断,会被放在两个数据结构里——tasklet_vec(普通tasklet)和tasklet_hi_vec(高优先级的tasklet)。
tasklet由tasklet_schedule()和tasklet_hi_schedule()进行调度,它接受一个指向tasklet_struct结构的指针作为参数。
执行步骤:
- 检查tasklet的状态,如果是TASKLET_STATE_SCHED则直接返回;
- 调用_tasklet_schedule();
- 保持中断状态,禁止本地中断;
- 把需要调度的tasklet加到链表里;
- 唤起软中断,这样在后面调用do_softriq()时执行这个tasklet;
- 恢复中断到原状态返回;
工作队列
工作队列是另一种将工作推后实现的机制,它是通过将工作交由一个内核线程在进程上下文执行的方法。工作队列可以重新调度,也可以睡眠。
下半部机制的选择
- 软中断处于中断上下文里,同类型的软中断能同时执行;
- tasklet处于中断上下文里,同类型不能同时执行;
- 工作队列处于进程上下文,能睡眠和唤醒;