日期:2014-05-16 浏览次数:20664 次
Linux的中断和时钟
对于linux学习中,一般是中断和时钟一起学习。在linux内核中,时钟的处理也是采用中断的方式,内核软件的定时也是最终要依赖于时钟,时钟要依赖于中断,所以中断是首先要学习的。
中断服务程序的执行是不需要存在于进程上下文的,所以这也要求中断是越短越好,也就是说我们不希望打扰原来的程序很长时间, 要尽快返回刚才的中断位置继续执行原来的程序。
中断源分类是很多的:1 可屏蔽中断,不屏蔽中断。2 向量中断和非向量中断。这俩个是根据不同分来方法分的。
学习linux中断,我想最主要还是学习linux中断处理架构。
从 linux1.x版本开始,中断处理程序从概念上被分为上半部分top half和下半部分bottom half。在中断发生时上半部分的处理 过程立即执行,因为它是完全屏蔽中断的,所以要快,否则其它的中断就得不到及时的处理。但是下半部分(如果有的话)几乎做了中断处理程序所有的事情,可以 推迟执行。内核把上半部分和下半部分作为独立的函数来处理,上半部分的功能就是“登记中断”,决定其相关的下半部分是否需要执行。需要立即执行的部分必须 位于上半部分,而可以推迟的部分可能属于下半部分。下半部分的任务就是执行与中断处理密切相关但上半部分本身不执行的工作,如查看设备以获得产生中断的时 间信息,并根据这些信息(一般通过读设备上的寄存器得来)进行相应的处理。从这里我们可以看出下半部分其实是上半部分引起的,例如当打印机端口产生一个中 断时,其中断处理程序会立即执行相关的上半部分,上半部分就会产生一个软中断(下半部分的一种)并送到操作系统内核里,这样内核就会根据这个软中断唤醒睡 眠的打印机任务队列中的处理进程。
上下部分图解
很多同学要问:为何要分为这两部分,让其中一部分去做,或者合并不是很好吗?
其实分为两部分的原因很简单,就是最快速有效的发现并执行中断。一般我们要求的是中断越快处理完毕越好,但是总是需要排队处理中断,这样上半部分就可以处理一些紧急事件,上半部分的剩余工作则会在稍候的任意时间执行,也就是在所谓的下半部分去执行。 总之,这样划分一个中断处理过程主要是希望减少中断处理程序的工作量(当然了,理想情况是将全部工作都抛给下半段。但是中断处理程序至少应该完成对中断请求的相应),因为在它运行期间至少会使得同级的中断请求被屏蔽,这些都直接关系到整个系统的响应能力和性能。而在下半段执行期间,则会允许响应所有的中断。 一句话就是说在性能和反应中断上做到综合处理。
对于上半部分和下半部分之间的划分没有严格的规则,靠驱动程序开发人员自己的编程习惯来划分,但是还是有一些习惯供参考:
Ⅰ.如果该任务对时间比较敏感,将其放在上半部中执行。
Ⅱ.如果该任务和硬件相关,一般放在上半部中执行。
Ⅲ.如果该任务要保证不被其他中断打断,放在上半部中执行(因为这是系统关中断)。
Ⅳ.其他不太紧急的任务,般考虑在下半部执行。
在上半部分中,中能采用的中断的形式处理程序。在下半部分中,可以采用tasklet,工作队列和软中断。
申请中断,释放中断,使能和屏蔽中断这里就不做介绍了,其实就是几个函数,只要记住就OK了。这里着重处理下下半部分的处理机制。
Work queue 工作队列
工作队列(work queue)是另外一种将工作推后执行的形式,它和前面讨论的tasklet有所不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被重新调度甚至是睡眠。
那么,什么情况下使用工作队列,什么情况下使用tasklet。如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后执行的任务不需要睡眠,那么就选择tasklet。另外,如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O