为了提高系统的响应能力和并发能力,Linux将中断处理分了上半部和下半部。当一个中断产生,调用该中断对应的处理程序(上半部),然后告诉系统,对应的后半部可以执行了,中断处理程序立即返回,下半部会在合适的时机由操作系统调用。这样一来就大大的减少了中断处理所需要的时间。
tasklet是中断处理下半部分最常用的一种方法,驱动程序一般先申请中断,在中断处理函数内完成中断上半部分的工作后调用tasklet。
一、tasklet的特点
- tasklet只可以在一个CPU上同步地执行,不同的tasklet可以在不同地CPU上同步地执行。
- tasklet的实现是建立在两个软件中断的基础之上的,即HI_SOFTIRQ和TASKLET_SOFTIRQ,本质上没有什么区别,只不过HI_SOFTIRQ的优先级更高一些
- 由于tasklet是在软中断上实现的,所以像软中断一样不能睡眠、不能阻塞,处理函数内不能含有导致睡眠的动作,如减少信号量、从用户空间拷贝数据或手工分配内存等。
- 一个 tasklet 能够被禁止并且之后被重新使能; 它不会执行直到它被使能的次数与被禁止的次数相同.
- tasklet的串行化使tasklet函数不必是可重入的,因此简化了设备驱动程序开发者的工作。
- 每个cpu拥有一个tasklet_vec链表,具体是哪个cpu的tasklet_vec链表,是根据当前线程是运行在哪个cpu来决定的。
二、tasklet结构体
1 | struct tasklet_struct { |
State域的取值为TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任务已被调度,正准备投入运行,TASKLET_STATE_RUN表示小任务正在运行。
Count域是小任务的引用计数器。如果它不为0,则小任务被禁止,不允许执行;只有当它为零,小任务才被激活,并且在被设置为挂起时,小任务才能够执行。
三、tasklet的定义
tasklet既可以静态创建也可以动态创建。 ### 1、静态创建
定义变量名为name的tasklets_struct变量,并初始化调用函数为func,参数为data,使能tasklet。
1
2
3DECLARE_TASKLET(name, func, data);
1
2
3DECLARE_TASKLET_DISABLED(name, func, data);
1
2
3
4
5
6
7
8void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
{
t->next = NULL; //
t->state = 0; //设置为未调度 未运行
atomic_set(&t->count, 0); //默认使能
t->func = func; //调用函数
t->data = data; //调用函数参数
}1
2static inline void tasklet_schedule(struct tasklet_struct *t);
tasklet_schedule(&my_tasklet); /*把 my_tasklet 标记为挂起 */1
2tasklet_disable(&my_tasklet); /* 小任务现在被禁止,这个小任务不能运行 */
tasklet_enable(&my_tasklet); /* 小任务现在被激活 */
五、tasklet相关函数
1 | void tasklet_disable(struct tasklet_struct *t); |
这个函数禁止给定的 tasklet. tasklet 可能仍然被 tasklet_schedule 调度,
但是它的执行被延后直到这个 tasklet 被再次使能. 如果这个 tasklet
当前在运行,这个函数忙等待直到这个 tasklet 退出; 因此, 在调用
tasklet_disable 后, 你可以确保这个 tasklet 在系统任何地方都不在运行.
1
void tasklet_disable_nosync(struct tasklet_struct *t);
1
void tasklet_enable(struct tasklet_struct *t);
1
void tasklet_schedule(struct tasklet_struct *t);
1
void tasklet_hi_schedule(struct tasklet_struct *t);
1
void tasklet_kill(struct tasklet_struct *t);
六、tasklet使用模板
1 | /* 定义tasklet和底半部函数并将它们关联 */ |