软中断和硬中断

从本质上讲,中断(硬)是一种电信号,当设备有某种事情发生的时候,他就会产生中断,通过总线把电信号发送给中断控制器。如果中断的线是激活的,中断控制器就把电信号发送给处理器的某个特定引脚。处理器于是立即停止自己正在做的事,跳到中断处理程序的入口点,进行中断处理。

产生中断请求的设备或者事件被称为中断源,中断源可分为两类:一类是CPU内部中断,即执行软件中断指令INT或遇到软件陷阱而产生的中断,它们的中断类型号已由CPU规定好;另一类中断是由CPU以外的I/O设备产生的中断,又称硬件中断,硬件中断可分为不可屏蔽中断NMI和可屏蔽中断INTR,NMI用于紧急情况的故障处理,如RAM奇偶校验错等,INTR则用于外部依靠中断来工作的硬件设备。网卡使用的就是INTR,下面我们对IRQ进行更深入的了解。

不可屏蔽中断源一旦提出请求,cpu必须无条件响应,而对于可屏蔽中断源的请求,cpu可以响应,也可以不响应。cup一般设置两根中断请求输入线:可屏蔽中断请求INTR(Interrupt Require)和不可屏蔽中断请求NMI(Nonmaskable Interrupt)。对于可屏蔽中断,除了受本身的屏蔽位的控制外,还都要受一个总的控制,即CPU标志寄存器中的中断允许标志位IF(Interrupt Flag)的控制,IF位为1,可以得到CPU的响应,否则,得不到响应。IF位可以有用户控制,指令STI或Turbo c的Enable()函数,将IF位置1(开中断),指令CLI或Turbo_c 的Disable()函数,将IF位清0(关中断)。典型的非屏蔽中断源的例子是电源掉电,一旦出现,必须立即无条件地响应,否则进行其他任何工作都是没有意义的。典型的可屏蔽中断源的例子是打印机中断,CPU对打印机中断请求的响应可以快一些,也可以慢一些,因为让打印机等待儿是完全可以的。

  1. 中断类型号和IRQ
    外部设备的中断请求是通过中断控制器8259A的INT引脚输入到CPU的INTR引脚向CPU提出中断申请的,并送去一个中断类型号,这是一个8位的二进制数。一片8259A能负责整个外部设备的中断请求(1RQ0-IRQ7),每个外设对应一个中断请求号。
中断类型号与中断请求号

2.IRQ的优先级和默认配置
一般计算机只能支持16个IRQ,也就是提供16个硬件设备的中断请求,16个IRQ是用两个8259A通过级联来实现的。

主从8259A连接图

主中断控制器8259A的IRQ2与从中断控制器8259A的INT引脚相连,因此从8259A上的中断请求优先级(Priority)享受主8259AIRQ2上的优先分级。所谓优先级是指当有多个中断源提出中断请求时,CPU先为优先权高的中断请求服务。再为优先权低的中断服务。主8259A中IRQ0~IRQ7中的IRQ0优先权最高,IRQ7最低;从8259A中以IRQ8最高,IRQ15最低。由于两个8259A的连接关系,从8259A的IRQ8~IRQ15的优先权低于主8259A的IRQ0~IRQ1,而高于主8259A的IRQ3~IRQ7。

中断优先级顺序

计算机中有些IRQ有默认的配置,这些默认的配置都是些常用设备,一般的默认配置。

IRQ默认配置使用情况

硬中断

  • 硬中断是由硬件产生的,比如,像磁盘,网卡,键盘,时钟等。每个设备或设备集都有它自己的IRQ(中断请求)。基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上(注:硬件驱动通常是内核中的一个子程序,而不是一个独立的进程)。

  • 处理中断的驱动是需要运行在CPU上的,因此,当中断产生的时候,CPU会中断当前正在运行的任务来处理中断。在有多核心的系统上,一个中断通常只能中断一颗CPU(也有一种特殊的情况,就是在大型主机上是有硬件通道的,它可以在没有主CPU的支持下,可以同时处理多个中断。)。

  • 硬中断可以直接中断CPU。它会引起内核中相关的代码被触发。对于那些需要花费一些时间去处理的进程,中断代码本身也可能被其他的硬中断中断。

  • 对于时钟中断,内核调度代码会将当前正在运行的进程挂起,从而让其他的进程来运行。它的存在是为了让调度代码(或称为调度器)可以调度多任务。

软中断

软中断是一组静态定义的下半部分接口,可以在所有的处理器上同时执行,即使两个类型相同也可以。但是一个软中断不会抢占另外的一个软中断,唯一可以抢占软中断的硬中断。

为了满足实时系统的要求,中断处理应该越快越好。编写驱动程序的时候,一个中断产生之后,内核在中断处理函数中可能需要完成很多工作。但是中断处理函数的处理是关闭了中断的。也就是说在响应中断时,系统不能再次响应外部的其它中断。这样的后果会造成有可能丢失外部中断。于是,linux内核设计出了一种架构,中断函数需要处理的任务分为两部分,一部分在中断处理函数中执行,这时系统关闭中断。另外一部分在软件中断中执行,这个时候开启中断,系统可以响应外部中断。
Linux为了实现这个特点,当中断发生的时候硬中断处理那些短时间,就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断(softirq)来完成。

  • 软中断的处理非常像硬中断。然而,它们仅仅是由当前正在运行的进程所产生的。

  • 通常,软中断是一些对I/O的请求。这些请求会调用内核中可以调度I/O发生的程序。对于某些设备,I/O请求需要被立即处理,而磁盘I/O请求通常可以排队并且可以稍后处理。根据I/O模型的不同,进程或许会被挂起直到I/O完成,此时内核调度器就会选择另一个进程去运行。I/O可以在进程之间产生并且调度过程通常和磁盘I/O的方式是相同。

  • 软中断仅与内核相联系。而内核主要负责对需要运行的任何其他的进程进行调度。一些内核允许设备驱动的一些部分存在于用户空间,并且当需要的时候内核也会调度这个进程去运行。

  • 软中断并不会直接的中断CPU。也只有当前正在运行的代码(或者是进程)才会产生软中断。这种中断是一种需要内核为正在运行的进程去做一些事情(通常是I/O)的请求。有一个特殊的软中断是Yield调用,他的作用是请求内核调度器去查看是否有其他的进程可以运行。

中断嵌套

Linux下硬中断是可以嵌套的,但是没有优先级的概念,也就是说任何一个新的中断都可以打断正在执行的中断,但同种中断除外。软中断不能嵌套,但相同类型的软中断可以在不同CPU上并行执行。

软中断指令

int是软中断指令。中断向量表是中断号和中断处理函数地址的对应表。int n - 触发软中断n。相应的中断处理函数的地址为:中断向量表地址 + 4 * n。

一些问题

  1. 对于软中断,I/O操作是否是由内核中的I/O设备驱动程序完成?
    答:对于I/O请求,内核会将这项工作分派给合适的内核驱动程序,这个程序会对I/O进行队列化,以可以稍后处理(通常是磁盘I/O),或如果可能可以立即执行它。通常,当对硬中断进行回应的时候,这个队列会被驱动所处理。当一个I/O请求完成的时候,下一个在队列中的I/O请求就会发送到这个设备上。

  2. 软中断所经过的操作流程是比硬中断的少吗?换句话说,对于软中断就是:进程 ->内核中的设备驱动程序;对于硬中断:硬件->CPU->内核中的设备驱动程序?
    答:是的,软中断比硬中断少了一个硬件发送信号的步骤。产生软中断的进程一定是当前正在运行的进程,因此它们不会中断CPU。但是它们会中断调用代码的流程。

  3. 硬中断和软中断的区别
    软中断是执行中断指令产生的,而硬中断是由外设引发的。
    硬中断的中断号是由中断控制器提供的,软中断的中断号由指令直接指出,无需使用中断控制器。
    硬中断是可屏蔽的,软中断不可屏蔽。
    硬中断处理程序要确保它能快速地完成任务,这样程序执行时才不会等待较长时间,称为上半部。
    软中断处理硬中断未完成的工作,是一种推后执行的机制,属于下半部。

如果硬件需要CPU去做一些事情,那么这个硬件会使CPU中断当前正在运行的代码。而后CPU会将当前正在运行进程的当前状态放到堆栈(stack)中,以至于之后可以返回继续运行。这种中断可以停止一个正在运行的进程;可以停止正处理另一个中断的内核代码;或者可以停止空闲进程。

推荐阅读更多精彩内容