一、简介tasklet是一种“延迟操作”机制,是通过
《软中断》来是实现的。
tasklet最大的特点是小任务不会同时执行,这样就不用显式地加锁,把同步的负担由驱动转移到了内核
单CPU情况:
特点1、schedule – schedule – run – schedule – run特点2、同一CPU上,同一tasklet只有一个实例运行
SMP情况:
特点3、在CPU_01上schedule过tasklet,必然会在CPU_01上执行tasklet,这个靠
《CPU私有变量》实现的
特点4、软中断在SMP下可能会同时运行,同一个tasklet保证在SMP下不会同时运行
每一个tasklet都有如下数据结构
- truct tasklet_struct{
-
struct tasklet_struct *next;
-
unsigned long state; //可选状态:TASKLET_STATE_SCHED 和 TASKLET_STATE_RUN
-
atomic_t count; //count值为0时,该task才使能,即允许执行
-
void (*func)(unsigned long); //钩子函数
-
unsigned long data; //钩子函数的形参
-
};
以下是两个tasklet_struct的CPU私有变量全局链表 (文件/kernel/softirq.c)
内核的所有tasklet_struct都由这两个链表串起来
- static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };
-
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL };
二、相关APIvoid tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
//初始化count(为0),func,data 这三个成员
void tasklet_schedule(struct tasklet_struct *t)
//检查tasklet状态,如果
TASKLET_STATE_SCHED,就啥都不做返回(
特点1明白了吧)
//否则,就设置状态为
TASKLET_STATE_SCHED,并把tasklet_struct放到当前调度的CPU的全局链表中去
void tasklet_enable(struct tasklet_struct *t); //使tasklet_struct.count减1
void tasklet_disable(struct tasklet_struct *t);//使tasklet_struct.count加1
void tasklet_kill(struct tasklet_struct *t); //将tasklet移除队列
三、tasklet的实现tasklet的软中断的注册
- start_kernel()
-
-->softirq_init()
-
-->open_softirq(TASKLET_SOFTIRQ, tasklet_action,NULL)
-
-->open_softirq(HI_SOFTIRQ,tasklet_hi_action,NULL)
tasklet的软中断的处理
- void __do_softirq(void)
-
{
-
//....省略
-
do {
-
if (pending & 1) {
-
h->action(h); //关键的一句,tasklet、内核timer、网络中断都是在这里搞的
-
rcu_bh_qsctr_inc(cpu);
-
}
-
h++;
-
pending >>= 1;
-
}while (pending);
-
//....省略
-
}
上面的h->action 就是先前注册的软中断处理例程 tasklet_action
- static void tasklet_action(struct softirq_action *a){
-
struct tasklet_struct *list;
-
local_irq_disable();
-
list = __get_cpu_var(tasklet_vec).list;
-
__get_cpu_var(tasklet_vec).list = NULL;
-
local_irq_enable();
-
-
while (list) {
-
struct tasklet_struct *t = list;
-
list = list->next;
-
if (tasklet_trylock(t)) { //这句保证在一个CPU上,同一个tasklet只有一个实例运行(特点2明白了吧)
-
if (!atomic_read(&t->count)) { //count值为0,tasklet才能执行
-
if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
-
BUG();
-
t->func(t->data); //这句执行tasklet上挂的钩子函数
-
tasklet_unlock(t);
-
continue;
-
}
-
tasklet_unlock(t);
-
}
-
local_irq_disable();
-
-
//此tasklet已在别的CPU上运行了,在此CPU上也要运行,再把tasklet加到队列中
-
t->next = __get_cpu_var(tasklet_vec).list;
-
__get_cpu_var(tasklet_vec).list = t;
-
__raise_softirq_irqoff(TASKLET_SOFTIRQ);
-
local_irq_enable();
-
}
-
}
阅读(2207) | 评论(0) | 转发(2) |