第七章 中断和中断处理(上半部)
一、中断
1、概念
由硬件设备发出的一种电信号,用于 处理器管理硬件设备,与之通信。不同设备对应的中断不同,每个中断通过中断请求(IRQ)线进行区分。
2、流程
- 由硬件设备产生,并送入中断控制器的引脚
- 中断控制器接收中断,并给处理器发生电信号
- 处理器检测到中断产生的电信号,便中断自己的当前工作转而处理中断
- 处理器通知操作系统中断已产生,由操作系统对中断进行处理
二、中断处理程序
1、概念
在响应一个特定的中断时,内核会执行的函数就叫做中断处理程序或中断服务例程,产生中断的每个设备都有一个与之对应的中断处理程序,中断处理程序是设备驱动程序(对设备进行管理的内核代码)的一部分 。
2、工作
中断处理程序主要处理以下两类工作,分别对应中断的上半部和下半部:
- 响应硬件应答(要求快,收到中断立即执行)
- 处理中断操作(处理大部分任务,推迟一段时间执行)
三、注册中断处理程序
1、概念
设备使用中断那么相应的驱动程序就要注册一个中断处理程序,对应函数为request_irq()
,成功返回0, 注意, request_irq()函数可能会睡眠,因此,不能在中断上下文或其他不允许阻塞的代码中调用该函数。
/*request_irq:分配一条给定的中断线*/
int request_irq (unsigned int irq, //中断号,有的动态分配,有的提前设置好了(例如时钟或键盘)
irq_handler_t handler, //指向实际的中断处理程序
unsigned long flags, //中断处理程序标志
const char *name, //中断相关设备的名字
void *dev) //用于共享中断线,提供中断线中的任意中断处理程序,可用于删除,且唯一
2、中断处理程序
实际执行的中断处理程序,P98页有使用实例。
static irq_handler_t intr_handler(int irq,void *dev) //irq与dev与注册时需要一致
3、中断处理程序标志
- IRQF_DISABLED:内核在处理中断处理程序本身不可被中断
- IRQF_SAMPLE_RANDOM:此标志表明这个设备产生的中断对内核熵池有贡献。内核嫡池负责提供从各种随机事件导出的真正的随机数。如果指定了该标志,可理解为中断处理的时间不确定
- IRQF_TIMER:该标志是特别为系统定时器的中断处理而准备的
- IRQF_SHARED:此标志表明可以在多个中断处理程序之间共享中断线
4、 释放中断处理程序
卸载驱动程序时,需要注销相应的中断处理程序,并释放禁用中断线(不共享的情况下)。共享则会删除对应的dev的处理程序 。
5、 重入和中断程序
Linux中的中断处理程序无须重入。当一个给定的中断处理程序正在执行时,相应的中断线在所有处理器上都会被屏蔽掉,以防止在同一中断线上接收另一个新的中断。通常情况下,所有其他的中断都是打开的,所以这些不同中断线上的其他中断都能被处理,但当前中断线总是被禁止的。由此可以看出,同一个中断处理程序绝对不会被同时调用以处理嵌套的中断。
void free_irq (unsigned int irq, void *dev)
四、中断上下文
1、进程上下文和中断上下文
-
进程上下文是一种内核所处的操作模式,此时内核代表进程执行,执行系统调用或运行内核线程。在进程上下文中,可以通过current宏关联当前进程。此外,因为进程是以进程上下文的形式连接到内核中的,因此,进程上下文可以睡眠,也可以调用调度程序。
-
中断上下文因为没有后备进程
(因为系统进入中断之前会关闭系统调用)
所以中断上下文不可以睡眠,否则怎么在对他重新调度?不能休眠,这使得中断处理程序所能进行的操作较之运行在进程上下文中的系统调用所能进行的操作受到了极大的限制。
注意
不能从中断上下文中调用某些函数。如果一个函数睡眠,就不能在你的中断处理程序中使用它。
五、中断处理机制的实现
1、完整中断处理流程
2、查看系统中断
cat /proc/interrupt
六、中断控制
1、概述
Linux内核提供了一组接口用于操作机器上的中断状态。这些接口为我们提供了能够禁止当前处理器的中断系统,或屏蔽掉整个机器的一条中断线的能力 。
2、 中断、锁和同步
控制中断系统的原因归根结底是需要提供同步。
- 锁提供保护机制,防止来自其他处理器的并发访问。
- 禁止中断提供保护机制,防止来自其他中断处理程序的并发访问。
Linux 支持多处理器,因此,内核代码一般都需要获取某种锁,防止来自其他处理器对共享数据的并发访问。获取这些锁的同时也伴随着禁止本地中断。 通过禁止中断,可以确保某个中断处理程序不会抢占当前的代码。此外,禁止中断还可以禁止内核抢占。