Tasklets
tasklets建立在软中断上的一种机制,它是一种软中断,但又与软中断不同,它有自己的特点:
1,可以动态创建和销毁。
2,在运行时,多次进行调度,此时也只能运行一次,并且调度时总是会让其在同一处理器上运行,如此可以很好的利用cache。
像进程一样,tasklet也由一个结构体来表示:
struct tasklet_struct
{
struct tasklet_struct *next; //链表上的下一个tasklets
unsigned long state; //tasklets的状态
atomic_t count; //引用数,表示这个tasklets是否被disable
void (*func)(unsigned long); //处理函数
unsigned long data; //处理函数的参数
};
tasklet的状态如下:
enum
{
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */ //相当于进程状态中的就绪状态,可以被调度运行
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */ //表示当前是否正处于运行状态
};
tasklet有两种形式的存在,一种是普通的tasklet,另一种是高优先级的tasklet,它们对应了两个软中断,分别为:TASKLET_SOFTIRQ
和HI_SOFTIRQ
在内核中定义如下:
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
这是两个双向链表,当某种类型的tasklet将被调度时,会把其挂到对应的链表下。
tasklet调度过程:
void __tasklet_schedule(struct tasklet_struct *t)
{
unsigned long flags;
local_irq_save(flags); //Disable本cpu的中断,并保存中断状态
t->next = NULL;
*__this_cpu_read(tasklet_vec.tail) = t; //把需要调度的tasklet加入到链表
__this_cpu_write(tasklet_vec.tail, &(t->next));
raise_softirq_irqoff(TASKLET_SOFTIRQ); //调度对应的软中断
local_irq_restore(flags); //Enable本cpu的中断,并恢复中断状态
}
如上函数对应的是普通tasklet,还有一个对应提高优先级的tasklets(__tasklet_hi_schedule),调用过程相似,只是需要触发HI_SOFTIRQ软中断。
静态定义tasklet
DECLARE_TASKLET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data);
动态定义tasklet
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
调度tasklet
void tasklet_schedule(struct tasklet_struct *t)
使能/禁用tasklet
void tasklet_enable(struct tasklet_struct *t)
void tasklet_disable(struct tasklet_struct *t)
void tasklet_disable_nosync(struct tasklet_struct *t)
tasklet_disable和tasklet_disable_nosync区别是如果此时tasklet正在运行,要等到运行结束tasklet_disable才能返回,tasklet_disable_nosync
则不用等待就可返回,它们的区别和中断中的两个接口(disable_irq/disable_irq_nosync)相似。
移除tasklet
void tasklet_kill(struct tasklet_struct *t) //等待tasklet运行结束,然后把tasklet从调度队列中移除。
注意:
tasklet_disable和tasklet_kill可能在调用时都需要等待,所以在中断处理函数中不能调用。