您的位置:首页 > 运维架构 > Linux

linux内核分析--为什么把中断分为上半部和下半步

2017-07-29 08:51 211 查看
写在前面:

       在讲解上半部和下半部的的由来前说明一下两者的分工。

   上半部:完成尽可能少的比较紧急的功能,它往往只是简单的读取寄存器中的中断状态并清除中断标志后就进行“登记中断”(也就是将底半部处理程序挂在到设备的底半部执行队列中的工作)
    特点:响应速度快
 
    下半部:中断处理的大部分工作都在底半部,它几乎做中断处理程序的所有事情。
    特点:处理相对来说不是非常紧急的事件


       中断服务例程一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。因此,内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。因此,内核把中断处理分为两部分:前半部分(top
half)和后半部分(bottom half),前半部分内核立即执行,而后半部分留着稍后处理,如图3.8所示:



 


图3.8中断的分割    

首先,一个快速的“前半部分”来处理硬件发出的请求,它必须在一个新的中断产生之前终止。通常地,除了在设备和一些内存缓冲区(如果你的设备用到了DMA,就不止这些)之间移动或传送数据,确定硬件是否处于健全的状态之外,这一部分做的工作很少。

然后,就让一些与中断处理相关的有限个函数作为“后半部分”来运行:

   ·允许一个普通的内核函数,而不仅仅是服务于中断的一个函数,能以后半部分的身份来运行。

   ·允许几个内核函数合在一起作为一个后半部分来运行。

后半部分运行时是允许中断请求的,而前半部分运行时是关中断的,这是二者之间的主要区别。      

       下半部的任务就是执行与中断处理密切相关但中断处理程序本生身不执行的任务。最好情况当然是中断处理程序把所有的工作都交給下半部执行,而自己啥都不做。因为我们总是希望中断处理程序尽可能快的返回。但是,中断处理程序注定要完成一部分工作。遗憾的是,并没有谁严格规定说什么任务应该在哪个部分中完成,换句话说,这个决定完全由想我们这样的驱动工程师来做。记住,中断处理程序会异步执行,并且在最好的情况下它也会锁定当前的中断线,因此将中断处理程序缩短的越小就越好。当然啦,没有规则并不是没有经验和教训:
1.如果一个任务对时间非常敏感,感觉告诉我还是将其放在中断处理程序中执行是个好的选择。

2.如果一个任务和硬件相关,还是将其放在中断处理程序中执行吧。

3.如果一个任务要保证不被其他中断(特别是相同的中断)打断,那就将其放在中断处理程序中吧。

4.其他所有任务,除非你有更好的理由,否则全部丢到下半部执行。
      总之,一句话:中断处理程序要执行的越快越好。

      我们前边老是说下半部会在以后执行,那么这个以后是个什么概念呢?遗憾的说,这个只是相对于马上而言的。下半部并需要指定一个明确的时间,只要把这个任务推迟一点,让他们在系统不太繁忙并且中断恢复后执行就可以了。通常下半部在中断处理程序已返回就会马上执行,关键在于当它们运行时,允许相应所有的中断。

       上半部只能通过中断处理程序来完成,下半部的实现却是有很多种方式。这些用来实现下半部的机制分别由不同的接口和子系统组成。最早的是“bottom half”,这种机制也被称为“BH”,它提供的接口很简单,提供了一个静态创建,由32个bottom half组成的链表,上半部通过一个32位整数中的一位来标识出哪个bottom half可执行。每个BH都在全局范围内进行同步,即使分属于不同的处理器,也不允许任何两个bottom
half同时执行。这种方式使用方便但不够灵活,简单却有性能瓶颈。以需要更好的方法了。第二种方法,任务队列(task queues).内核定义了一组队列。其中每个队列都包含一个由等待调用的函数组成链表。根据其所处队列的位置,这些函数会在某个时刻被执行,驱动程序可根据需要把它们自己的下半部注册到合适的队列上去。这种方法已经不错,但仍然不够灵活,它没办法代替整个BH接口。对于一些性能要求较高的子系统,像网络部分,它也不能胜任。在2.3开发版中,又引入了软中断(softirqs)和tasklet,这里的软中断和实现系统调用所提到的软中断(软件中断)不是同一个概念。如果无须考虑和过去开发的驱动程序相兼容的话,
软中断和tasklet可以完全代替BH接口。软中断是一组静态定义的下半部接口,有32个,可以在所有的处理器上同时执行----即使两个类型完全相同。task是一种基于软中断实现的灵活性强,动态创建的下半部实现机制。两个不同类型的tasklet可以在不同的处理器上同时执行,但类型相同的tasklet不能同时执行。tasklet其实是一种在性能和易用性之间寻求平衡的产物。软中断必须在编译期间就进行静态注册,而tasklet可以通过代码进行动态注册。现在都是2.6内核了,我们说点新鲜的吧,linux2.6内核提供了三种不同形式的下半部实现机制:软中断,tasklets和工作对列,这些会依次介绍到。这时,可能有人会想到定时器的概念,定时器也确实是这样,但定时器提供了精确的推迟时间,我们这里还不至于这样,所以先放下,我们后面再说定时器 
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: