第7章 中断和中断处理
操作系统的核心任务之一-对连接上的硬件进行管理(硬盘、键盘、鼠标等)。要想管理这些硬件,就需要可以和他们进行通信。硬件的反应要远远慢于CPU,轮询会耗费大量CPU资源,显然不适合,那就是通过中断机制来实现。
7.1 中断
(1)中断本质上是一种特殊的电信号。由硬件设备发向处理器。
(2)中断随时可产生,内核随时可能被到来的中断所打断。
(3)每个中断都有唯一的数字标识,操作系统得以对中断进行区分。
(4)硬件发出的中断是为了引起内核的关注,“嗨,我有新的按键需要处理,读取并处理这些操作把”。
(5)异常:异常与中断不同,异常产生时必须与处理器时钟同步。异常也常常称为同步中断。
(6)系统调用是一种异常,来进入内核。
(7)中断是由硬件引起的,而不是软件。
7.2 中断处理程序
(1)在响应一个中断的时候,内核会执行中断处理程序,或者称为中断服务程序。
(2)产生中断的每个设备都有一个相应的中断处理程序。
(3)一个设备的中断处理程序,是它设备驱动程序的一部分。设备驱动程序是用于对设备管理的内核代码。
(4)Linux中,设备驱动程序是C函数而已,只是需要按照特定的类型声明。
(5)中断处理程序是被内核调用来响应中断的,运行于中断上下文的特殊上下文中(该上下文代码不可被阻塞)。
(6)中断随时发生,中断服务程序随时可能被执行,因此需要保证中断处理程序可以快速执行。
(7)中断服务程序需要告诉硬件,我听到你了,现在回去工作吧。即需要对硬件应答,同时可能需要进行数据拷贝等操作。如网络设备中断。
7.3 上半部与下半部对比
(1)中断处理为了执行快,而且可执行的内容多,因此被分为上半部和下半部。
(2)
- 上半部:中断处理程序,接收一个中断,它就立刻开始执行,只做有严格时限的工作,例如对接受的中断进行硬件应答或者复位硬件。
- 下半部:允许稍后完成的工作。Linux提供了实现下半部的各种机制。
(3)网卡例子
上半部:
网卡发出中断:hi内核,我有数据来了。内核执行网卡中断处理程序来做出应答。拷贝最新网络数据包到内存中,因为网卡缓存有限,不及时拷贝,数据可能丢失,拷贝后上半部分完成。
下半部:
处理和操作数据包。
7.4 注册中断处理程序
(1)中断处理程序是驱动程序的组成部分。驱动程序可以通过request_irq()函数注册一个中断处理程序。并且激活给定的中断线,以处理中断。
(2)request_irq()在<linux/interrupt.h>中
int request_irq(unsignedint irq,irq_handler_t handler,unsigned long flags,const char * name,void *dev)参数解析:
- 第一个参数irq:
要分配的中断号。
- 第二个参数handler:
是一个指针,指向处理这个中断的中断处理程序。只有操作系统一接受到中断,这个函数就会被调用。
7.4.1 中断处理程序标志
- 第三个参数flags:
可以是0,也可以是一个或多个标志的位掩码<linux/interrupt.h>。
- 第四个参数name:
与中断相关的设备的ASCII文本表示,这些名字会被/proc/irq和/proc/interrupts文件使用,以便与用户通讯。
- 第五个参数dev:
用于共享中短线,如果无需共享中断线,那么该参数设置成NULL即可。当中断处理程序需要释放的时候,dev将提供唯一的标识信息(cookie),以便从共享中断线诸多中断处理程序中删除指定的哪一个。
- 返回值:
执行成功返回:0。非零则失败。
注意:
request_irq()函数可能休眠,不能在中断上下文或其他不允许阻塞的代码中调用,由于kmalloc()可能休眠。
7.4.2 一个中断例子
7.4.3 释放中断处理程序
(1)卸载驱动的时候,需要注销相应的中断线。调用
Void free_irq(unsigned int irq , void *dev)(2)如果中断线不是共享的,该函数删除处理程序的同时,将禁用这条中断线。如果是共享的,则仅删除dev对应的处理程序,中断线只有在删除了最后一个处理程序时才被禁止。
7.5 编写中断处理程序
中断处理程序函数声明
static irqreturn_t intr_handler(int irq,void *dev)
- 参数irq:中断号
- 参数dev:通用指针,与传递给request_irq()的dev一致。可以用来区分共享同一中断处理程序的多个设备。
- 返回值irqreturn_t:实际为一个int。中断处理程序被正常调用,且确实是它所对应设备产生中断时返回IRQ_HANDLER。
7.6 中断上下文
(1)当执行一个中断处理程序时,内核处于中断上下文中。
(2)中断上下文不可以休眠,具有较为严格的时间限制。
(3)回忆:进程上下文是一种内核所处的操作模式,此时内核代表进程执行,如执行系统调用或者运行内核线程,进程上下文可以休眠,也可以调用调度程序。
(4)中断处理程序尽可能的迅速,简洁,尽可能把工作从中断处理程序中独立出来,放在下半部执行,因为下半部可以在更适合的时间执行。
7.7 中断处理机制的实现(待深入)
(1)中断处理系统在Linux中的实现非常依赖于体系结构
7.8 /proc/interrupts
(1)procfs是一个虚拟文件系统,只存在于内核内存中,一般安装与/proc目录。
(2)/proc/interrupts中存放了系统中与中断相关的统计信息。
7.9 中断控制
7.9.1 禁止和激活中断
(1)用于禁止和激活当前处理器上的本地中断。
7.9.2 禁止指定中断线
(1)仅禁止整个系统中的某一条中断线。
7.9.3 中断系统的状态
(1)获取中断系统的状态(禁止or激活),是否处于中断上下文的执行状态。
(2)中断控制方法列表
7.10 小结
中断是一种由设备使用的硬件资源异步的向处理器发信号,中断就是由硬件来打断操作系统。