tasklet是基于软中断实现的一种下半部机制。tasklet和软中断在本质上很相似,行为表现也很相近。
tasklet的实现:
tasklet有两类软中断代表:HI_SOFTIRQ和TASKLET_SOFTIRQ,这两者之间唯一的实际区别在于,HI_SOFTIRQ类型的软中断先于TASKLET_SOFTIRQ类型的软中断执行。
tasklet结构体,中定义:
struct tasklet_struct {
struct tasklet_struct *next;/*链表中的下一个tasklet。正是因为tasklet使用链表形式实现的,所以使得tasklet可以被动态的创建多个*/
unsigned long
state;/*tasklet的状态。三种取值:0、TASKLET_STATE_SCHED和TASKLET_STATE_RUN(只用于在多CPU
情况下进行优化使用,因为同种类型的tasklet处理程序在同一时间只能运行一个),单CPU上tasklet状态要么是0(没在运行),要么是
TASKLET_SATE_SCHED(正在运行)*/
atomic_t count;/*引用计数器,用于标记tasklet是否为激活状态,只有当count为0时才会被激活运行*/
void (*func)(unsigned long);/*tasklet的处理程序*/
unsigned long data;/*传递给tasklet处理程序的参数*/
};
tasklet的调度:
可以类比于softirq的触发,
1)softirq通过raise_softirq或raise_softirq_irqoff函数触发软中断,而tasklet通过
tasklet_schedule(HI_SOFTIRQ也类似,以下均已TASKLET_SOFTIRQ为例)进行触发tasklet,当然必须首先得
触发TASKLET_SOFTIRQ软中断。
static inline void tasklet_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))//在同一时刻只能有一个tasklet在执行
__tasklet_schedule(t);
}
void fastcall __tasklet_schedule(struct tasklet_struct *t)
{
unsigned long flags;
local_irq_save(flags);
t->next = __get_cpu_var(tasklet_vec).list;
//触发tasklet,其实就是把tasklet加到tasklet_vec链表中去
__get_cpu_var(tasklet_vec).list = t;
raise_softirq_irqoff(TASKLET_SOFTIRQ);
//触发软中断
local_irq_restore(flags);
}
2)softirq在执行时(do_softirq),流程为:关中断->获取待处理的softirq位图-->逐个执行softirq的处
理程序;tasklet也一样,由于tasklet是基于软中断的,所以也得通过do_softirq执行,当遍历到TASKLET_SOFTIRQ时,
执行tasklet_action函数。在tasklet_action函数中去处理待处理的tasklet。通过分析tasklet_action函
数,可以看出,其实现思路与do_softirq实现思路很相似:
static void tasklet_action(struct softirq_action *a)
{
struct tasklet_struct *list;
local_irq_disable();
//关中断
list = __get_cpu_var(tasklet_vec).list;
//获取待处理的tasklet链表
__get_cpu_var(tasklet_vec).list = NULL;
//将tasklet链表清空
local_irq_enable();
//打开中断,意味着tasklet在执行的时候是可能被中断打断的。
while (list) {//遍历链表,执行待处理的tasklet
struct tasklet_struct *t = list;
list = list->next;
if (tasklet_trylock(t)) {
if (!atomic_read(&t->count)) {
if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
BUG();
t->func(t->data);
tasklet_unlock(t);
continue;
}
tasklet_unlock(t);
}
local_irq_disable();
t->next = __get_cpu_var(tasklet_vec).list;
__get_cpu_var(tasklet_vec).list = t;
__raise_softirq_irqoff(TASKLET_SOFTIRQ);
local_irq_enable();
}
}
阅读(2159) | 评论(0) | 转发(0) |