[笔记]《Linux内核设计与实现》第七、八章中断处理

目前正在通读《Linux内核设计与实现》一书,本文是对第七章<中断和中断处理>、第八章<下半部和推后执行的工作>的总结。一些细节,不知道是翻译的原因还是本身就比较晦涩,看完之后没怎么看明白。

1.几个概念:
1.1.中断:中断就是由硬件来打断操作系统。中断本质上是一种特殊的电信号,由硬件设备发向处理器。处理器接收到中断后,会马上向操作系统反映信号的到来,然后由操作系统负责处理这些新到来的数据。
中断可以随时产生,内核随时可能因为新到来的中断而被打断。
1.2.中断控制器:是一个电子芯片,其作用是将多路中断管线,采用复用技术只通过一个和处理器相连接的管线与处理器通信。
1.3.中断线:不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标志。这些中断值通常被称为中断请求(IRQ)线。
1.4.异常:处理器本身产生的同步中断。它在产生时必须考虑与处理器时钟同步。
1.5.中断处理程序:在响应一个特定中断的时候,内核会执行一个函数。该函数叫做中断处理程序(interrupt handler)或中断服务例程(interrupt service routine,ISR)。
中断处理程序是设备驱动程序的一部分。设备驱动程序是用于对设备进行管理的内核代码。
在Linux中,中断处理程序就是普普通通的C函数,与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的,它们运行于中断上下文,也称作原子上下文,该上下文中的执行代码不可阻塞。
中断处理程序是和特定中断关联的,一个设备可以产生多种不同的中断,所以该设备就可以对应多个中断处理程序,相应的,该设备的驱动程序也就需要准备多个这样的函数。
另外,中断处理程序可以共享同一个中断线。
1.5.1request_irq()
驱动程序通过request_irq()函数注册一个中断处理程序,request_irq()函数可能会睡眠,原因是其内部实现中会调用函数kmalloc()来请求分配内存,函数kmalloc()是可以睡眠的。
因此不能在中断上下文或其他不允许阻塞的代码中调用该函数。
内核接收到一个中断后,它将依次调用在该中断线上注册的每一个处理程序。
1.6.进程上下文:此时内核代表进程执行,如执行系统调用或运行内核线程。
1.7.中断上下文:此时内核执行一个中断处理程序,因为没有后备进程,所以中断上下文不可以睡眠。中断处理程序打断了其他的代码。
在2.6版本早期的内核中,内核栈的大小从两页减小为一页,中断处理程序有了自己的栈,每个处理器一个,大小为一页。

2.上半部和下半部
中断处理程序会异步执行,并且在最好的情况下它也会锁定当前的中断线。最起码的,中断处理程序要负责通知硬件设备中断已被接收。
不仅仅是Linux,许多操作系统也把处理硬件中断的过程分为两个部分。
上半部分(top half)简单快速,执行的时候禁止一些或者全部中断。只能通过中断处理程序实现。只做有严格时限的工作。
下半部分(bottom half)稍后执行,而且执行期间可以响应所有的中断。
这种设计可使系统处于中断屏蔽状态的时间尽可能的短,以此来提高系统的响应能力。
2.1.划分工作的参考规则:
2.1.1.任务对时间非常敏感,放在中断处理程序中执行;
2.1.2.任务和硬件相关,放在中断处理程序中执行;
2.1.3.任务要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行
2.1.4.其他所有任务,考虑放在下半部执行。

3.下半部机制
在当前2.6版本的内核中,有三种可用的下半部机制:软中断、tasklet和工作队列(task queue)。
3.1.软中断
软中断是一组静态定义的下半部接口,有32个。
软中断必须在编译期间就进行静态注册。
软中断使用较少,软中断保留给系统中对时间要求最严格以及最重要的下半部使用。目前,只有两个子系统(网路和SCSI)直接使用软中断。
一个软中断不会抢占另外一个软中断。实际上,唯一可以抢占软中断的是中断处理程序。
一个注册的软中断必须在被标记后才会执行。这被称作触发软中断(raising the softirq).
通常,中断处理程序会在返回前标记它的软中断,使其在稍后被执行。
大部分软中断处理程序,都通过采取单处理器数据(仅属于某一个处理器的数据,因此根本不需要加锁)或者其他一些技巧来避免显式地加锁。
引入软中断的主要原因是其可扩展性。如果不需要扩展到多个处理器,那么就使用tasklet。
软中断处理程序的时候,允许响应中断,但它自己不能睡眠。在一个处理程序运行的时候,当前处理器上的软中断被禁止。而其他的处理器仍可以执行别的或者同类型的软中断。
软中断和tasklet运行在中断上下文
3.2.tasklet
tasklet,基于软中断实现,不同的是类型相同的tasklet不能在多个处理器上同时执行,而且tasklet可以通过代码进行动态注册。
3.2.1.软中断内核程序
每个处理器都有一组辅助处理软中断(和tasklet)的内核线程。软中断在执行的时候,它可以重新触发自己以便再次得到执行。针对这个问题的这种方案是:内核不会立即处理重新触发的软中断。内核会唤起这组软中断内核线程来处理这些负载,这些线程在最低优先级上运行(nice值是19)。
3.3.工作队列
工作队列子系统是一个用于创建内核线程的接口,它创建的这些内核线程称作工作者线程(worker thread)。缺省的工作者线程叫做events/n,n是处理器的编号。驱动程序或者子系统,默认使用缺省线程。
工作队列将下半部的任务放在进程上下文中完成,允许重新调度甚至是睡眠。
3.4.内核定时器
此外,内核定时器也可以用于下半部的工作。内核定时器也是建立在软中断之上的。当你必须保证在一个确定的时间段过去以后再运行时,就应该使用内核定时器。
3.5.下半部机制的选择:
任务需要休眠吗?需要的话选择工作队列;否则就用tasklet,要是必须专注于性能的提高,那就考虑软中断。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值