Linux(内核剖析):23---中断下半部之(下半部总体概述)

Posted 董哥的黑板报

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux(内核剖析):23---中断下半部之(下半部总体概述)相关的知识,希望对你有一定的参考价值。

一、为什么要下半部
  • 在前面的文章中,我们讨论了内核为处理中断而提供的中断处理程序机制。中断处理程序是内核中很有用的(实际上也是必不可少的)部分。但是,由于本身存在一些局限,所以它只能完成整个中断处理流程的上半部分。这些局限包括:
    • 1.中断处理程序以异步方式执行,并且它有可能会打断其他重要代码(甚至包括其他中断处 理程序) 执行。因此,为了避免被打断的代码停止时间过长,中断处理程序应该执行得越快越好
    • 2.如果当前有一个中断处理程序正在执行,在最好的情况下(如果IRQF_DISABLED没有被设置 ),与该中断同级的其他中断会被屏蔽,在最坏的情况下(如果设置了IRQF_ DISABLED),当前处理器上所有其他中断都会被屏蔽。因为禁止中断后硬件与操作系统无法通信,因此,中断处理程序执行得越快越好
    • 3.由于中断处理程序往往需要对硬件进行操作,所以它们通常有很高的时限要求
    • 4.中断处理程序不在进程上下文中运行,所以它们不能阻塞。这限制了它们所做的事情
  • 现在,为什么中断处理程序只能作为整个硬件中断处理流程一部分的原因就很明显了。操作系统必须有一个快速、异步、简单的机制负责对硬件做出迅速响应并完成那些时间要求很严格的操作。中断处理程序很适合于实现这些功能,可是,对于那些其他的、对时间要求相对宽松的任 务,就应该推后到中断被激活以后再去运行
  • 这样,整个中断处理流程就被分为了两个部分,或叫两半。第一个部分是中断处理程序(上半部 ),就像我们在前面中断文章讨论的那样,内核通过对它的异步执行完成对硬件中断的即时响应。 在接下来的几篇文章中,我们要研究的是中断处理流程中的另外那一部分,下半部(bottom halves)
二、下半部
  • 下半部的任务就是执行与中断处理密切相关但中断处理程序本身不执行的工作。在理想的情况下,最好是中断处理程序将所有工作都交给下半部分执行,因为我们希望在中断处理程序中完成的工作越少越好(也就是越快越好)。我们期望中断处理程序能够尽可能快地返回
  • 但是,中断处理程序注定要完成一部分工作。例如,中断处理程序几乎都需要通过操作硬件对中断的到达进行确认,有时它还会从硬件拷贝数据。因为这些工作对时间非常敏感,所以只能靠中断处理程序自己去完成剩下的几乎所有其他工作都是下半部执行的目标。例如,如果你在上半部中把数据从硬件拷 贝到了内存,那么当然应该在下半部中处理它们。遗憾的是,并不存在严格明确的规定来说明到底什么任务应该在哪个部分中完成— 如何做决定完全取决于驱动程序开发者自己的判断。尽管 在理论上不存在什么错误,但轻率的实现效果往往不很理想。记住,中断处理程序会异步执,并且在最好的情况下它也会锁定当前的中断线。因此将中断处理程序持续执行的时间缩短到最小程度显得非常重要
  • 对于在上半部和下半部之间划分工作,尽管不存在某种严格的规则,但还是有一些提示可供借鉴:
    • 1.如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
    • 2.如果一个任务和硬件相关,将其放在中断处理程序中执行
    • 3.如果一个任务要保证不被其他中断(特别是相同的中断)大端,将其放在中断处理程序中 执行。
    • 4.其他所有任务,考虑放置在下半部执行
  • 当你开始尝试写自己的驱动程序的时候,读一下别人的中断处理程序和相应的下半部可能会让你受益匪浅。在决定怎样把你的中断处理流程中的工作划分到上半部和下半部中去的时候,问问自己什么必须放进上半部而什么可以放进下半部。通常,中断处理程序要执行得越快越好
三、为什么要用下半部
  • 理解为什么要让工作推后执行以及在什么时候推后执行非常关键
  • 你希望尽最减少中断处理程序中需要完成的工作量,因为它在运行的时候,当前的中断线在所有处理器上都会被屏蔽。 更糟糕的是,如果一个处理程序是IRQF_DISABLED类型,它执行的时候会禁止所有本地中断 (而且把本地中断线全局地屏蔽掉)。而缩短中断被屏蔽的时间对系统的响应能力和性能都至关重要。再加上中断处理程序要与其他程序(甚至是其他的中断处理程序)异步执行,所以很明显,我们必须尽力缩短中断处理程序的执行。解决的方法就是把一些工作放到以后去做
  • 但具体放到以后什么时候去做呢?
    • 在这里,以后仅仅用来强调不是马上而已,理解这一点相当重要
    • 下半部并不需要指明一个确切时间,只要把这些任务推迟一点,让它们在系统不太繁忙并且中断恢复后执行就可以了
    • 通常下半部在中断处理程序一返回就会马上运行。下半部执行的关键在于当它们运行的时候,允许响应所有的中断
  • 不仅仅是Linux, 许多操作系统也把处理硬件中断的过程分为两个部分:
    • 上半部分简单快 速,执行的时候禁止一些或者全部中断
    • 下半部分(无论具体如何实现)稍后执行,而且执行期间可以响应所有的中断
    • 这种设计可使系统处于中断屏蔽状态的时间尽可能的短,以此来提高系统的响应能力
四、下半部的环境(下半部的实现机制)
  • 和上半部只能通过中断处理程序实现不同,下半部可以通过多种机制实现。这些用来实现下半部的机制分别由不同的接口和子系统组成。在前面中断的文章中,我们了解到实现中断处理程序的方法只有一种(就是中断处理程序),但在本章中你会发现,实现一个下半部会有许多不同的方法
  • 实际上,在Linux展的过程中曾经出现过多种下半部机制。让人备受困扰的是,其中不少机制名字起得很相像,甚至还有一些机制名字起得词不达意。这就需要专门的程序员来给下半部命名。
  • 在接下来几篇文章中,我们将讨论2.6版本的内核中的下半部机制是如何设计和实现的。同时我们也会讨论怎么在自己编写的内核代码中使用它们。而那些过去使用的、已经废除了有一段时间的机制,由于曾经闻名遐迩,所以在相关的时候我们还是会有所提及。

①“下半部”的起源

  • 最早的Linux只提供“bottom half”这种机制用于实现下半部。这个名字在那时毫无异义,因为当时它是将工作推后的唯一方法。这种机制也被称为“BH”,我们现在也这么叫它,以避免和“下半部”这个通用词汇混淆
  • 像过往的那段美好岁月中的许多东西一样,BH接口也非常简 单。它提供了一个静态创建、由32个bottom halves组成的链表。上半部通过一个32位整数中的一位来标识出哪个bottom half可以执行。每个BH都在全局范围内进行同步。即使分属于不同的处理器,也不允许任何两个bottom half时执行。这种机制使用方便却不够灵活,简单却有性能瓶颈

②任务队列

  • 不久,内核开发者们就引入了任务队列(task queue) 机制来实现工作的推后执行,并用它来代替BH机制。内核为此定义了一组队列,其中每个队列都包含一个由等待调用的函数组成链表。根据其所处队列的位置,这些函数会在某个时刻执行。驱动程序可以把它们自己的下半部注册到合适的队列上去
  • 这种机制表现得还不错,但仍不够灵活,没法代替整个BH接口。对于一些性能要求较高的子系统,像网络部分,它也不能胜任

③软中断和tasklet

  • 在2.3这个开发版本中,内核开发者引入了软中断(softirqs) 和tasklet。如果无须考虑和过去开发的驱动程序兼容的话,软中断和tasklet可以完全代替BH接口
    • 软中断:是一组静态定义的下半部接口,有32个,可以在所有处理器上同时执行——即使两个类型相同也可以
    • tasklet:这一名称起得很糟糕,让人费解,它们是一种基于软中断实现的灵活性强、动态创建的下半部实现机制。两个不同类型的tasklet可以在不同的处理器上同时执行,但类型相同的tasklet不能同时执行。tasklet其实是一种在性能和易用性之间寻求平衡的产物
  • 对于大部分下半部处理来说,用tasklet就足够了,像网络这样对性能要求非常高的情况才需要使用软中断。可是,使用软中断需要特別小心,因为两个相同的软中断有可能同时执行。此外,软中断还必须在编译期间就进行静态注册。与此相反,tasklet可以通过代码进行动态注册
  • 有些人被这些概念彻底搞糊涂了,他们把所有的下半部都当成是软件产生的中断或软中断。 换句话说,就是他们把软中断机制和下半部统统都叫软中断。別管他们好了。软中断与BH和 tasklet并驾其名

工作队列

  • 在开发2.5版本的内核时,BH接口最终被弃置了,所有的BH使用者必须转而使用其他下 半部接口。此外,任务队列接口也被工作队列接口取代了。工作队列是一种简单但很有用的方法,它们先对要推后执行的工作排队,稍后在进程上下文中执行它们。稍后的内容中我们再来探究它们
  • 综上所述,在2.6这个当前版本中,内核提供了三种不同形式的下半部实现机制:软中断、 tasklets和工作队列

内核定时器

  • 另外一个可以用于将工作推后执行的机制是内核定时器。不像本章到目前为止介绍到的所有这些机制,内核定时器把操作推迟到某个确定的时间段之后执行。也就是说,尽管本章讨论的其他机制可以把操作推后到除了现在以外的任何时间进行,但是当你必须保证在一个 确定的时间段过去以后再运行时,你应该使用内核定时器
  • 较之本章讨论到的这些机制,定时器还有一些其他功能。有关定时器的详细内容在后面的文章会讨论
五、总结
  • 这些东西确实把人搅得很混乱,但它们其实只不过是一些起名的问题,让我们再来梳理一遍
    • “下半部(bottom half)”是一个操作系统通用词汇,用于指代中断处理流程中推后执行的 那一部分,之所以这样命名,是因为它表示中断处理方案一半的第二部分或者下半部。在 Linux 中,这 词目前确实就是这个含义。所有用于实现将工作推后执行的内核机制都被称为“下半部 机制”。 一 些人错误地把所有的下半部机制都叫做“软中断”,真是在自寻烦恼。
    • “下半部”这个词也指代Linux最早提供的那种将工作推后执行的实现机制。由于该机制也被叫做“BH ”,所以,我们就使用它的这个名称,而让 “下半部”这个词仍然保持它通常的含 义。BH机制很早以前就被反对使用了,在2.5版内核中,全就被完全去除了
    • 当前,有三种机制可以用来实现将工作推后执行:软中断、tasklet和工作队列。tasklet通过软中断实现,而工作队列与它们完全不同
  • 下标揭示了下半部机制的演化历程

以上是关于Linux(内核剖析):23---中断下半部之(下半部总体概述)的主要内容,如果未能解决你的问题,请参考以下文章

把握linux内核设计思想:下半部机制之软中断

Linux内核中的下半部机制之tasklet

Linux内核中的下半部机制之tasklet

Linux中断底半部机制

《Linux内核设计与实现》读书笔记- 中断下半部的处理

Linux内核实现中断和中断处理