软中断及tasklet

我们前面在”中断处理”一节提到,在由内核执行的几个任务之间有些不是紧急的的;在必要情况下它们可以廷迟一段时间。回忆一下,一个中断处理程序的几个中断服务例程之间的串行执行的。并且通常在一个中断的处理程序结束前,不应该再次出现这个中断。相反,可廷迟中断可以在开中断的情况下执行。把可廷迟中断从中断处理程序中抽出来有助于使内核保持较短的响应时间。这对于那些期望它们的中断能在几毫秒内得到处理的”急迫”应用来说是非常重要的。

Linux2.6迎接这种挑战是通过两种非紧迫、可中断内核函数:所谓的可廷迟函数和通过工作队列来执行的函数。

软中断和tasklet有密切的关系,tasklet是在软中断之上实现。事实上,出现在内核代码中的术语”软中断”常常表示可廷迟函数的所有种类。另外一种被广泛使用的术语是”中断上下文”;表示内核当前正执行一个中断处理程序或一个可廷迟的函数。

软中断的分配是静态的,而tasklet的分配和初始化可以在运行是进行。软中断可以并发地运行在多个CPU上。因此,软中断是可重入函数而且必须明确地使用自旋锁保护其数据结构。tasklet不必担心这些问题,因为内核对tasklet的执行了更加严格的控制。相同类型的tasklet总是被串行地执行,换句话说就是:不能在两个CPU上同时运行相同类型的tasklet。但是,类型不同的tasklet可以在几个CPU上并发执行。tasklet的串行化使tasklet函数不必是可重入的,因此简化了设备驱动程序开发者的工作。

一般而言,在可廷迟函数上可以执行四种操作:

初始化

定义一个新的可廷迟函数;这个操作通常在内核自身初始化或加载模块时进行。

激活

标记一个可廷迟函数为”挂起”。激活可以在任何时候进行。

屏蔽

有选择地屏蔽一个可延迟函数,这样,即使它被激活,内核也不执行它。我们会在第五章”禁止和激活可延迟函数”一节看到,禁止可延迟函数有时是必要的。

执行

执行一个挂起的可延迟函数和同类型的其它所有挂起的可延迟函数;执行是在特定的时间进行的,这将在后面”软中断”一节解释。

激活和执行不知何故总是捆绑在一起;由给定CPU激活的一个可延迟函数必须在同一个CPU上执行。没有什么明显的理由说明这条规则对系统性能是有益的。把可延迟函数绑定在激活CPU上从理论上说可以理好利用CPU的硬件高速缓存。毕竟,可以想象,激活的内核线程访问的一些数据结构,可延迟函数也可能会使用。然后,当可延迟函数运行时,因为它的执行可以延迟一段时间,因此相关高速缓存行很可能就不再在高速缓存中了。此外,把一个函数绑定在一个CPU上总是有潜在”危险的”操作,因为一个CPU可能忙死而其它CPU又无所事事。

软中断


Linux2.6使用有限个软中断。在很多场合,tasklet是足够用的,且更容易编写,因为tasklet不必是可重入的。

事实上,如表4-9所示,目前只定义了六种软中断。


一个软中断的下标决定了它的优先级:低下标意味着高优先级,因为软中断函数将从下标0开始执行。

软中断所使用的数据结构

表示软中断的主要数据结构是softirq_vec数组,该数组包含类型为softirq_action32个元素,一个软中断的优先级是相应的softirq_action元素在数组内的下标。如表4-9所示,只有数组的前六个元素被有效地使用。softirq_action数据结构包括两个字段;指向软中断函数的一个action指针和指向软中断函数需要的通过数据结构的data指针。

另外一个关键的字段是32位的preempt_count字段,用它来跟踪内核抢占和内核控制路径的嵌套,该字段存放在每个进程描述符的thread_info字段中。如表4-10所示,preempt_count字段的编码表示三个不同的计数器和一个标志。


第一个计数器记录显式禁用本地CPU内核抢占的次数,值等于0表示允许内核抢占。第二个计数器表示可延迟函数被禁用的程度。第三个计数器表示在本地CPU上中断处理程序的嵌套数。

preempt_count字段起这个名字的理由是很充分的:当内核代码明确不允许发生抢占或当内核下在中断上下文中运行是,必须禁用内核的抢占功能。因此,为了确定是否能够抢占当前进程,内核快速检查preempt_count字段中的相应值是否等于0。在第五章”内核抢占”一节将深入讨论内核抢占。

in_interrupt()检查current_thread_info()->preempt_count字段的硬中断计数器和软中断计数器,只要这两个计数器中的一个值为正数,该宏就产生一个非零值否则产生一个零值。如果内核不使用多内核栈,则该宏只检查当前进程的thread_info描述符的preempt_count字段。但是,如果内核使用多内核栈,则该宏可能还要检查本地CPUirq_ctx联合体中thread_info描述符的preempt_count字段。在这种情况下,由于该字段总是正数值,所以宏返回非零值。

实现软中断的最后一个关键的数据结构是每个CPU都有的32位掩码,它存放在irq_cpustat_t数据结构的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值