[Linux概念学习]6 中断和中断处理

1、为什么有中断?

处理器需要管理很多硬件,不可能每次等到这个硬件完毕再去下一个,也不好挨个轮询问。

->中断:硬件在需要的时候主动向处理器发出信号

中断随时产生,处理器随时被打断,不考虑处理器时钟同步,非常任性。


2、中断本质上是电信号。

  1. 中断由硬件设备(比如键盘)产生,然后送入中断控制器的输入引脚。
  2. 中断控制器的另一端与处理器相连,接收一个中断后,就会给处理器发送电信号;
  3. 处理器收到信号,就会中断自己当前任务,转去处理中断,然后通知操作系统已经产生中断。
  4. 由操作系统处理中断。



3、操作系统需要给不同中断提供不同的中断处理程序,那它是如何区别不同设备的中断?

通过唯一的数字标志——中断请求线IRQ。

IRQ0:时钟中断

IRQ1:键盘中断

也可能是动态分配,只要内核知道匹配关系,特定中断号与特定设备关联。


4、异常(同步中断)

  1. 异常是软件引起,然后处理器来产生——因为编程失误或者执行时的特殊情况,必须靠内核处理时
  2. 产生时必须考虑与处理器的时钟同步
  3. 内核对中断和异常的处理非常类似


5、中断处理程序

每个产生中断的设备都有一个相应的中断处理程序。

但1个中断处理程序可以处理等多个设备的中断。

  1. 中断处理程序就是普通C函数,只不过必须按照特定的类型声明。
  2. 中断处理程序运行于叫做中断上下文的特殊上下文中。
  3. 中断随时发生,中断处理程序也随时可能执行,因此必须保证它能够快速执行,才能保证尽快恢复中断代码的执行。(对发起中断的硬件,迅速对其中断进行服务;对其他部分,让中断处理程序进款完成运行切回原来的任务)


6、中断处理程序分上半部和下半部

1)为什么要分?

既要中断处理程序快速结束,又希望中断处理程序做很多的事情???

2)上半部:接收到一个中断,就立即开始执行,但只做有严格时限的工作

下半部:能够被允许稍后完成的工作会推迟到下半部。

3)举例:网卡接收到数据,向内核发出中断

上半部:通知硬件,拷贝数据包到内存

下半部:处理和操作数据包



7、在中断线上注册中断处理程序request_irq()

一般是硬件的驱动程序来完成注册,中断处理程序是驱动程序的一部分。


其中,

1)irq表示要分配的中断号

2)handler是指针,指向实际处理这个中断的中断处理程序。操作系统一接到中断,这个函数就会被调用。



3)flags是中断处理标志

4)name是与硬件设备相关的ascii文本表示。比如,键盘中断对应“keyborad”

5)dev用于共享中断线。


注册中断处理程序的示例:



8、释放中断处理程序free_irq()

卸载驱动程序时,需要注销相应的中断处理程序,如果中断线非共享,还要同时禁用中断线。

如果中断线是共享,则不禁用中断线,但是需要有唯一标志dev来指定需要删除的是哪一个处理程序(dev非空),此时必须从进程上下文中调用free_irq()。?



9、编写中断处理程序



共享的处理程序与非共享的主要差异主要有3处:

1)request_irq()的flags设置共享

2)dev唯一,以区分共享中断处理程序的不同设备

3)中断处理程序必须能够区分它的设备是否真的产生了中断。因为内核接收1个中断后,会依次调用在中断线上的所有处理程序,由处理程序自己必须知道是自己的设备发出了中断,还是共享这条中断线的其他设备发出了中断。


例子:RTC设备的驱动——RTC驱动

RTC驱动程序装在时,rtc_init()函数被调用,职责之一就是在rtc_irq上注册rtc_interrupt。

当操作系统一接收到RTC中断,就会执行这段中断处理程序:



10、中断上下文:

当执行一个中断处理程序时,内核处于中断上下文。


进程上下文 && 中断上下文

1)进程上下文中,内核代表进程执行


2)而中断上下文与进程、current宏毫无联系

  1. 不可以睡眠、可以调用的函数也有限制(比如不能调用睡眠函数)
  2. 有严格的时间限制



11、中断处理机制的实现



12、profs文件系统与/proc/interrupts文件

1)profs是一个虚拟文件系统,只存在系统内核,在其中读写文件都要调用内核函数,这些函数模拟从真实文件中的读或者写。

2)相关的例子,就是/proc/interrupts文件,存在于系统中中断相关的统计信息。

proc/interrupts文件内容有4列:



13、中断控制

linux内核提供了一组接口,用于操作机器上的中断状态:

  1. 能够禁止当前处理器的中断系统
  2. 能够屏蔽掉整个机器的一条中断线


提供中断控制的原因:需要提供同步——禁止中断,以确保当前代码不会被某个中断处理程序抢占,也可以禁止内核抢占。

但中断控制,禁止的是中断处理程序的并发访问,而不能防止来自多个处理器的并发访问——那需要加锁保护。获取锁的同时也伴随着禁止当前处理器上的本地中断。


1)禁止当前处理器上的本地中断


但是可能在disable之前已经是disable,而enable也是无条件执行不考虑是否具有条件,因此有一些危险

-》在disable之前保存中断系统的状态,在准备激活中断时,恢复。


废除全局禁止中断cli():

以前,任何访问共享数据的地方都可以使用cli()进行互斥访问,cli()能够禁止系统中所有处理器上的中断(全局禁止中断),直到调用sti()激活。

而现在这个接口取消,需要做更多工作——结合使用本地中断控制和自旋锁。

2)禁止一条中断线

有时候不用禁止处理器,禁止一条中断线就够了,但注意禁止多个处理器共享的中断线是不合适的!


3)中断系统的状态

通常情况下,需要了解是出于进程上下文还是中断上下文。

irqs_diable():如果本地处理器上的中断系统被禁止,则返回0,否则非0。

in_interrupt():如果内核正在执行中断处理或者下半部,都返回非0;否则处于进程上下文,返回0

in_irq():只有在内核确实正在执行中断处理程序时才返回非0。


14、总结

编辑于 2018-12-31

文章被以下专栏收录