kernel中断分析七——tasklet
来源:互联网 发布:正的网络外部性 编辑:程序博客网 时间:2024/06/04 21:02
Abstract
在Kernel 中断分析六——softirq中,分析了软中断的处理流程,那么bottom half还剩下tasklet与workqueue。tasklet是在软中断基础上实现的一种延迟机制,当然同样运行在中断上下文,而workqueue运行在进程上下文,允许睡眠。
Tasklet
kernel中有定义了十种软中断类型,其中HI_SOFTIRQ、TASKLET_SOFTIRQ用于实现tasklet,区别在于HI_SOFTIRQ的优先级较高。
tasklet_struct
kernel中用tasklet_struct来描述一个tasklet,用DECLARE_TASKLET来声明一个tasklet。
443 /* Tasklets --- multithreaded analogue of BHs.444445 Main feature differing them of generic softirqs: tasklet-----1446 is running only on one CPU simultaneously.447448 Main feature differing them of BHs: different tasklets-------2449 may be run simultaneously on different CPUs.450451 Properties:452 * If tasklet_schedule() is called, then tasklet is guaranteed453 to be executed on some cpu at least once after this.454 * If the tasklet is already scheduled, but its execution is still not455 started, it will be executed only once.456 * If this tasklet is already running on another CPU (or schedule is called457 from tasklet itself), it is rescheduled for later.458 * Tasklet is strictly serialized wrt itself, but not459 wrt another tasklets. If client needs some intertask synchronization,460 he makes it with spinlocks.461 */462463 struct tasklet_struct464 {465 struct tasklet_struct *next;466 unsigned long state;467 atomic_t count;468 void (*func)(unsigned long);469 unsigned long data;470 };471472 #define DECLARE_TASKLET(name, func, data) \473 struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
在分析代码之前先说明tasklet的特点,以便带着问题分析。
以上的注释概括了tasklet的核心思想:
1. 与普通软中断的区别在于:相同的tasklet同一时间只能在一个CPU上执行,即相同tasklet不具有并发性,相同的tasklet串行执行。
2. 与其他BHs(其实就是softirq和workqueue)的区别在于:不同的tasklet可以同时运行在不同的CPU上。不同的tasklet并行执行。
总结以上两条,可以发现软中断和tasklet的区别:
softirq:软中断可以并发运行在不同CPU上,即多个CPU可能同时调用同一块软中断处理的代码,所以软中断处理是可重入的,这就要求软中断处理函数中访问数据时做好保护工作。
tasklet:相同的tasklet在不同处理器上串行执行,不同的tasklet可在不同处理器上并行执行。即tasklet不需要考虑重入,比如,对于某个driver的tasklet,任何时刻,只有一个CPU会执行相关的代码片。
tasklet_schedule
509 static inline void tasklet_schedule(struct tasklet_struct *t)510 {511 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) ------1512 __tasklet_schedule(t);513 }
446 void __tasklet_schedule(struct tasklet_struct *t)447 {448 unsigned long flags;449450 local_irq_save(flags); -------2451 t->next = NULL; -------3452 *__this_cpu_read(tasklet_vec.tail) = t; -------4453 __this_cpu_write(tasklet_vec.tail, &(t->next));454 raise_softirq_irqoff(TASKLET_SOFTIRQ); -------5455 local_irq_restore(flags); -------6456 }457 EXPORT_SYMBOL(__tasklet_schedule);443 static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec); -------4435 /*436 * Tasklets437 */438 struct tasklet_head {439 struct tasklet_struct *head;440 struct tasklet_struct **tail;441 };
- tasklet_schedule表示将要schedule传入的tasklet,如果该tasklet已经被设置了TASKLET_STATE_SCHED,则退出;否则调用__tasklet_schedule。这说明,同一个tasklet,在处于schedule状态下,再尝试进行schedule,实际上只处理一次。
- 禁用本地CPU中断
- 只schedule一个tasklet,将其next指针设置成NULL
- 将该tasklet加入到tasklet_vec链表中尾部。kernel为每个CPU定义了一个tasklet_vec链表,保存需要schedule的tasklet。
- 触发TASKLET_SOFTIRQ对应的软中断,前几篇分析的很详细了。
- 打开本地中断
tasklet_action
TASKLET_SOFTIRQ软中断触发以后会调用对应的中断处理函数,即tasklet_action
482 static void tasklet_action(struct softirq_action *a)483 {484 struct tasklet_struct *list;485486 local_irq_disable(); ------------1487 list = __this_cpu_read(tasklet_vec.head); ----2488 __this_cpu_write(tasklet_vec.head, NULL); -----3489 __this_cpu_write(tasklet_vec.tail, &__get_cpu_var(tasklet_vec).head);490 local_irq_enable(); --------4491492 while (list) { ---------------------5493 struct tasklet_struct *t = list; -----5.1494495 list = list->next; -----5.2496497 if (tasklet_trylock(t)) { -----5.3498 if (!atomic_read(&t->count)) { -----5.4499 if (!test_and_clear_bit(TASKLET_STATE_SCHED,-----5.5500 &t->state))501 BUG();502 t->func(t->data); -------5.6503 tasklet_unlock(t); -------5.7504 continue;505 }506 tasklet_unlock(t);507 }508509 local_irq_disable(); --------6510 t->next = NULL; 511 *__this_cpu_read(tasklet_vec.tail) = t;512 __this_cpu_write(tasklet_vec.tail, &(t->next));513 __raise_softirq_irqoff(TASKLET_SOFTIRQ);514 local_irq_enable();515 }516 }
- 关闭本地CPU中断
- 获取tasklet_vec链表
- 清空tasklet_vec链表
- 打开本地CPU中断
- 判断list是否为空
5.1 获取第一个tasklet
5.2 获取下一个tasklet,方便下一次遍历
5.3 检测TASKLET_STATE_RUN有没有被设置,如果有,说明该tasklet正在其他CPU上处理。否则设置该状态位为1,表示该tasklet正在本地CPU上被处理。此时其他CPU如果调用tasklet_action,会tasklet_trylock失败,进入step 6。
5.4 tasklet的count表示该tasklet是否被disable,0 enable,1 disable。如果被disable,那么清除TASKLET_STATE_RUN,进入step6。
5.5 检测TASKLET_STATE_SCHED标志位是否为0,如果为0,那么此时抛一个bug出来,因为正常情况下,前面的处理流程中设置了TASKLET_STATE_SCHED为1,并且其他CPU是没有机会再设置TASKLET_STATE_SCHED的。如果为1,那么清0,此时TASKLET_STATE_SCHED为0,TASKLET_STATE_RUN为1,tasklet从schedule状态变成了run状态。
5.6 执行tasklet的处理函数
5.7 清除该tasklet的TASKLET_STATE_RUN标志位,并且调用continue进入下一次循环。 - 走到这一步,有两种可能:
a. tasklet_trylock失败,该tasklet正在被其他CPU处理
b. 该tasklet被disable了
以上两种情况都会将TASKLET_STATE_RUN标志位清0,并将该tasklet添加到tasklet_vec的尾部,重新触发一次TASKLET_SOFTIRQ软中断,等待下一次处理。所以,无论tasklet能否顺利执行,该tasklet始终运行在schedule它的CPU上
可以想象一下,tasklet_vec中有N个tasklet,满足条件的tasklet会调用它的处理函数。如果有tasklet正在其他CPU上运行,那么本CPU上与之相同的tasklet放到tasklet_vec尾部,下一次再处理。如此就实现了相同tasklet串行执行。至于不同的tasklet,在多个CPU上并发执行时没问题的。
- kernel中断分析七——tasklet
- kernel 中断分析五——irq_thread
- Kernel 中断分析六——softirq
- linux kernel 下半部 软中断 tasklet
- linux kernel的中断子系统之:tasklet
- x86 kernel 中断分析三——中断处理流程
- kernel 中断分析之四——中断申请[上]
- kernel 中断分析之四——中断申请 [下]
- linux软件中断——tasklet机制
- linux软件中断——tasklet机制
- linux内核中断 ----- tasklet 分析
- linux内核中断 ----- tasklet 分析
- linux内核中断 ----- tasklet 分析 .
- linux内核中断 ----- tasklet 分析
- [linux中断]中断下半部分——tasklet
- x86 kernel 中断机制分析一——IDT
- x86 kernel 中断机制分析二——irq_desc
- linux 中断底半部之tasklet分析
- ButterKnife配置
- OpenCV3.0 Examples学习笔记(5)-distrans.cpp
- 北京天宇联科技有限责任公司—T语言html页面开发
- Error:java: Compilation failed: internal java compiler error
- android View 事件分发
- kernel中断分析七——tasklet
- 微信应用号(小程序)开发IDE配置
- 总结下在开发项目中禁用按钮的一些小方法
- wordexp函数的使用
- Hibernate 的三种查询方式:HQL、Criteria、Sql
- Tensorflow 训练结果为 NAN
- webpack资料
- Fast Visual Tracking via Dense Spatio-Temporal Context Learning 论文笔记
- OAF 系列教程 五 更新UPDATE