参考:http://blog.csdn.net/tiangwan2011/article/details/7254752
从 linux1.x版本开始,中断处理程序从概念上被分为上半部分(tophalf)和下半部分(bottomhalf)。在中断发生时上半部分的处理 过程立即执行,因为它是完全屏蔽中断的,所以要快,否则其它的中断就得不到及时的处理。但是下半部分(如果有的话)几乎做了中断处理程序所有的事情,可以 推迟执行。内核把上半部分和下半部分作为独立的函数来处理,上半部分的功能就是“登记中断”,决定其相关的下半部分是否需要执行。需要立即执行的部分必须 位于上半部分,而可以推迟的部分可能属于下半部分。下半部分的任务就是执行与中断处理密切相关但上半部分本身不执行的工作,如查看设备以获得产生中断的时 间信息,并根据这些信息(一般通过读设备上的寄存器得来)进行相应的处理。从这里我们可以看出下半部分其实是上半部分引起的,例如当打印机端口产生一个中 断时,其中断处理程序会立即执行相关的上半部分,上半部分就会产生一个软中断(下半部分的一种)并送到操作系统内核里,这样内核就会根据这个软中断唤醒睡 眠的打印机任务队列中的处理进程。
中断上下部分分解
为什么要将一个中断分为如此两部分?下面的几个经典原因可以很好的诠释这个问题。
1.中断可以随时的打断处理机对其他程序的执行,如果被打断的代码对系统很重要,那么此时中断处理程序的执行时间应该是越短越好。
2.通过上文我们知道,中断处理程序正在执行时,会屏蔽同条中断线上的中断请求;而更严重的是,如果设置了IRQF_DISABLED,那么该中断服务程序执行是会屏蔽所有其他的中断请求。那么此时应该让中断处理程序执行的越快越好。
上面的几个例子都要求中断服务程序的执行时间越短越好。一般的,中断处理程序会在上半部分执行。而事实上,几乎所有的情况,上半部分就只执行中断处理程序。因此,我们可以这样认为:一个完整的中断处理流程是由中断处理程序和下半部分共同完成的。
这样划分是有一定原因的,因为我们必须有一个快速、异步而且简单的处理程序专门来负责对硬件的中断请求做出快速响应,与此同时也要完成那些对时间要求很严格的操作。而那些对时间要求相对宽松,其他的剩余工作则会在稍候的任意时间执行,也就是在所谓的下半部分去执行。
总之,这样划分一个中断处理过程主要是希望减少中断处理程序的工作量(当然了,理想情况是将全部工作都抛给下半段。但是中断处理程序至少应该完成对中断请求的相应。),因为在它运行期间至少会使得同级的中断请求被屏蔽,这些都直接关系到整个系统的响应能力和性能。而在下半段执行期间,则会允许响应所有的中断。和上半段只能通过中断处理程序实现不同的是,下半部可以通过多种机制来完成:小任务(tasklet),工作队列,软中断。
中断上下两部分最大的不同是上半部分不可中断,而下半部分可中断。在理想的情况下,最好是中断处 理程序上半部分将所有工作都交给下半部分执行,这样的话在中断处理程序上半部分中完成的工作就很少,也就能尽可能快地返回。但是,中断处理程序上半部分一 定要完成一些工作,例如,通过操作硬件对中断的到达进行确认,还有一些从硬件拷贝数据等对时间比较敏感的工作。剩下的其他工作都可由下半部分执行。
对于上半部分和下半部分之间的划分没有严格的规则,靠驱动程序开发人员自己的编程习惯来划分,但是还是有一些习惯供参考:
Ⅰ.如果该任务对时间比较敏感,将其放在上半部中执行。
Ⅱ.如果该任务和硬件相关,一般放在上半部中执行。
Ⅲ.如果该任务要保证不被其他中断打断,放在上半部中执行(因为这是系统关中断)。
Ⅳ.其他不太紧急的任务,般考虑在下半部执行。
下半部分并不需要指明一个确切时间,只要把这些任务推迟一点,让它们在系统不太忙并且中断恢复后执行就可以了。通常下半部分在中断处理程序一返回就会马上运 行,下半部分执行的关键在于当它们运行的时候,允许响应所有的中断。下半部分是一种推后执行任务,它将某些不那么紧迫的任务推迟到系统更方便的时刻运行。 内核中实现下半部的手段不断演化,目前已经从最原始的BH(bottomhalf)衍生出BH(在2.5中去除)、软中断(softirq在2.3引 入)、tasklet(在2.3引入)、工作队列(workqueue在2.5引入)。这里主要分析讨论后三种方式。