将中断处理分成top half(cpu和外设之间的交互,获取状态,ack状态,收发数据等)和bottom half(后段的数据处理)已经深入人心,对于任何的OS都一样,将不那么紧急的事情推迟到bottom half中执行是OK的,具体如何推迟执行分成两种类型:有具体时间要求的(对应linux kernel中的低精度timer和高精度timer)和没有具体时间要求的。对于没有具体时间要求的又可以分成两种:
1、越快越好型,这种实际上是有性能要求的,除了中断top half可以抢占其执行,其他的进程上下文(无论该进程的优先级多么的高)是不会影响其执行的,一言以蔽之,在不影响中断延迟的情况下,OS会尽快处理。
2、随遇而安型。这种属于那种没有性能需求的,其调度执行依赖系统的调度器。
本质上讲,越快越好型的bottom half不应该太多,而且tasklet的callback函数不能执行时间过长,否则会产生进程调度延迟过大的现象,甚至是非常长而且不确定的延迟,对real time的系统会产生很坏的影响。
在linux kernel中,“越快越好型”有两种,softirq 和 tasklet,“随遇而安型”也有两种,workqueue 和threaded irq handler。
tasklet 特点:
1、tasklet可以动态分配,也可以静态分配,数量不限。
2、同一种 tasklet 在多个cpu上也不会并行执行,这使得程序员在撰写 tasklet function 的时候比较方便,减少了对并发的考虑(当然损失了性能)。
3、tasklet 在软件中断上下文中运行,所以 tasklet 代码必须是原子的。而工作队列函数在一个特殊内核进程上下文运行,有更多的灵活性,且能够休眠。4、tasklet 执行的很快, 短时期, 并且在原子态,除了中断top half可以抢占其执行,其他的进程上下文(无论该进程的优先级多么的高)是不会影响其执行的。
tasklet 使用:
Tasklet 的使用比较简单,只需要定义tasklet及其处理函数并将两者关联
例子:
Void my_tasklet_func(unsigned long)
静态创建:static DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)
动态创建:DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)
代码 DECLARE_TASKLET 实现了定义名称为 my_tasklet 的 tasklet 并将其与 my_tasklet_func 这个函数绑定,而传入这个函数的参数为data。
需要调度 tasklet 的时候引用一个 tasklet_schedule() 函数就能使系统在适当的时候进行调度,如下所示
Tasklet_schedule(&my_tasklet)