《深入理解Linux内核》笔记4:软中断_tasklet_工作队列葡萄的技术博客百度空间
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
软中断、tasklet 和工作队列并不是Linux 内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half )演变而来。下半部的机制实际上包括五种, 但2.6 版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者。本文重点在于介绍这三者之间的关系。(函数细节将不会在本文中出现,可以参考文 献,点这里) (1 )上半部和下半部的区别 上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务。举个例子:在网络传输中,网卡接收到数据包这个事件不一定需要 马上被处理,适合用下半部去实现;但是用户敲击键盘这样的事件就必须马上被响应,应该用中断实现。 两者的主要区别在于:中断不能被相同类型的中断打断,而下半部依然可以被中断打断;中断对于时间非常敏感,而下半部基本上都是一些可以延迟的工作。由于二 者的这种区别,所以对于一个工作是放在上半部还是放在下半部去执行,可以参考下面四条: a )如果一个任务对时间非常敏感,将其放在中断处理程序中执行。 b )如果一个任务和硬件相关,将其放在中断处理程序中执行。 c)如果一个任务要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行。 d )其他所有任务,考虑放在下半部去执行。 (2 )为什么要使用软中断? 软中断作为下半部机制的代表,是随着SMP (share memory processor )的出现应运而生的,它也是tasklet 实现的基础(tasklet 实际上只是在软中断的基础上添 加了一定的机制)。软中断一般是“可延迟函数”的总称,有时候也包括了tasklet (请读者在遇到的时候根据上下文推断是否包含tasklet )。它的出现就是因为要满足 上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个CPU 上并行执行,使得总的系统效率可以更高。它的特性包括: a )产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被硬件中断打断(上半部)。 b )可以并发运行在多个CPU 上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU 同时操作),因此也需要使用自旋锁来保护其数据 结构。 (3 )为什么要使用tasklet?(tasklet和软中断的区别) 由于软中断必须使用可重入函数,这就导致设计上的复杂度变高,作为设备驱动程序的开发者来说,增加了负担。而如果某种应用并不需要在多个CPU 上并行执行, 那么软中断其实是没有必要的。因此诞生了弥补以上两个要求的tasklet 。它具有以下特性: a )一种特定类型的tasklet 只能运行在一个CPU 上,不能并行,只能串行执行。 b )多个不同类型的tasklet 可以并行在多个CPU 上。 c)软中断是静态分配的,在内核编译好之后,就不能改变。但tasklet 就灵活许多,可以在运行时改变(比如添加模块时)。 tasklet 是在两种软中断类型的基础上实现的,但是由于其特殊的实现机制(将在4.3 节详细介绍),所以具有了这样不同于软中断的特性。而由于这种特性,所以降 低了设备驱动程序开发者的负担,因此如果不需要软中断的并行特性,tasklet 就是最好的选择。 (4 )可延迟函数(软中断及tasklet)的使用 一般而言,在可延迟函数上可以执行四种操作:初始化/ 激活/ 执行/ 屏蔽。屏蔽我们这里不再叙述,前三个则比较重要。下面将软中断和tasklet 的三个步骤分别进行对 比介绍。 (4.1 )初始化 初始化是指在可延迟函数准备就绪之前所做的所有工作。一般包括两个大步骤:首先是向内核声明这个可延迟函数,以备内核在需要的时候调用;然后就是调用相应 http://hi.baidu.com/microgrape/blog/item/6c851ddcad954e3c5882dde6.html[2011/4/19 10:51:48]
Biblioteka Baidu
上一篇:《深入理解Linux内核》笔记3:中...
已有3人分享了这篇文章:
gjzhangjian Ta的分享
zkj3e Ta的分享
neversaynot Ta的分享
网友评论:
1 2010年11月24日 星期三 14:13 | 回复 很好 emmix
发表评论:
内 容:
发表评论
?2011 Baidu
http://hi.baidu.com/microgrape/blog/item/6c851ddcad954e3c5882dde6.html[2011/4/19 10:51:48]
《深入理解Linux内核》笔记4:软中断/tasklet/工作队列_葡萄的技术博客_百度空间 的初始化函数,用函数指针等初始化相应的描述符。 如果是软中断则在内核初始化时进行,其描述符定义如下:
struct softirq_action { void ( * action)( struct softirq_action * ); void * data; };
open_softirq(NET_TX_SOFTIRQ,net_tx_action); open_softirq(NET_RX_SOFTIRQ,net_rx_action);
这样初始化完成后实际上就完成了一个一一对应的关系:当内核中产生到NET_TX_SOFTIRQ 软中断之后,就会调用net_tx_action 这个函数。 tasklet 则可以在运行时定义,例如加载模块时。定义方式有两种: 静态声明
open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
因此,这两个软中断是要被区别对待的。tasklet_action 和tasklet_hi_action 内部实现就是为什么软中断和tasklet 有不同的特性的原因(当然也因为二者的描述符不 同,tasklet 的描述符要比软中断的复杂,也就是说内核设计者自己多做了一部分限制的工作而减少了驱动程序开发者的工作)。 (5 )为什么要使用工作队列work queue ?(work queue 和软中断的区别) 上面我们介绍的可延迟函数运行在中断上下文中(软中断的一个检查点就是do_IRQ 退出的时候),于是导致了一些问题:软中断不能睡眠、不能阻塞。由于中断上 下文出于内核态,没有进程切换,所以如果软中断一旦睡眠或者阻塞,将无法退出这种状态,导致内核会整个僵死。但可阻塞函数不能用在中断上下文中实现,必须 要运行在进程上下文中,例如访问磁盘数据块的函数。因此,可阻塞函数不能用软中断来实现。但是它们往往又具有可延迟的特性。 因此在2.6 版的内核中出现了在内核态运行的工作队列(替代了2.4 内核中的任务队列)。它也具有一些可延迟函数的特点(需要被激活和延后执行),但是能够能够 在不同的进程间切换,以完成不同的工作。
《深入理解Linux内核》笔记4:软中断/tasklet/工作队列_葡萄的技术博客_百度空间 用户名: 密码:
Submit 登录
注册
葡萄的技术博客
主要是C++/兼有其他技术。。。
主页
博客
相册
|
个人档案
|
好友
|
i贴吧
查看文章
《深入理解Linux内核》笔记4:软中断/tasklet/工作队列
2009年06月02日 星期二 10:48
其参数分别为描述符,需要调用的函数和此函数的参数—必须是unsigned long 类型。也需要用户自己写一个类似net_tx_action 的函数指针func 。初始化最终生成的 结果就是一个实际的描述符,假设为my_tasklet (将在下面用到)。 (4.2 )激活 激活标记一个可延迟函数为挂起(pending )状态,表示内核可以调用这个可延迟函数(即使在中断过程中也可以激活可延迟函数,只不过函数不会被马上执行); 这种情况可以类比处于TASK_RUNNING 状态的进程,处在这个状态的进程只是准备好了被CPU 调度,但并不一定马上就会被调度。 软中断使用raise_softirq() 函数激活,接收的参数就是上面初始化时用到的数组索引nr 。 tasklet 使用tasklet_schedule() 激活,该函数接受tasklet 的描述符作为参数,例如上面生成的my_tasklet :
tasklet_schedule( & my_tasklet)
(4.3 )执行 执行就是内核运行可延迟函数的过程,但是执行只发生在某些特定的时刻(叫做检查点,具体有哪些检查点?详见《深入》p.177 )。 每个CPU 上都有一个32 位的掩码__softirq_pending ,表明此CPU 上有哪些挂起(已被激活)的软中断。此掩码可以用local_softirq_pending() 宏获得。所有的挂 起的软中断需要用do_softirq() 函数的一个循环来处理。 而对于tasklet ,由于软中断初始化时,就已经通过下面的语句初始化了当遇到TASKLET_SOFTIRQ/HI_SOFTIRQ 这两个软中断所需要执行的函数:
DECLARE_TASKET(name, func, data) DECLARE_TASKLET_DISABLED(name, func, data)
动态声明
void tasklet_init(struct tasklet_struct * t, void ( * func)(unsigned long ), unsigned long data)
http://hi.baidu.com/microgrape/blog/item/6c851ddcad954e3c5882dde6.html[2011/4/19 10:51:48]
《深入理解Linux内核》笔记4:软中断/tasklet/工作队列_葡萄的技术博客_百度空间
类别:Linux |
| 分享到i贴吧 | 浏览(2131) | 评论 (1) 下一篇:Linux Cross Reference Linux内...
在\kernel\softirq.c 文件中包括了32 个描述符的数组static struct softirq_action softirq_vec[32] ;但实际上只有前6 个已经被内核注册使用(包括tasklet 使用 的HI_SOFTIRQ/TASKLET_SOFTIRQ 和网络协议栈使用的NET_TX_SOFTIRQ/NET_RX_SOFTIRQ ,还有SCSI 存储和系统计时器使用的两个),剩下的可以由 内核开发者使用。需要使用函数: void open_softirq(int nr, void (*action)(struct softirq_action*), void *data) 初始化数组中索引为nr 的那个元素。需要的参数当然就是action 函数指针以及data 。例如网络子系统就通过以下两个函数初始化软中断 (net_tx_action/net_rx_action 是两个函数):