中断和异常

中断(interrupt)被定义为一个事件,该事件改变处理器执行的指令顺序,这样的事件与CPU芯片内外部硬件电路产生的电信号相对应。中断通常分为同步(synchronous)中断和异步(asynchronous)中断。

  1. 同步中断指的是当指令执行时由CPU控制单元产生的,之所以称为同步,是因为只有在一条指令终止执行后CPU才会发出中断。
  2. 异步中断是由其他硬件设备依照CPU时钟信号随机产生的。

在Intel处理器中,把同步中断和异步中断分别称为异常(exception)和中断(interrupt)。我们这里也采用这种分类。我们也使用中断信号来统称中断和异常。

中断是由间隔定时器和I/O设备产生的,例如,用户的一次按键会引起一个中断,虽然用户没有感觉,但是按键这个过程到下一次按键之间的间隔对于计算机指令时间来说是非常长的。

另一方面,异常是由程序的错误产生的1,或者由内核必须处理的异常条件产生的。第一种情况下,内核通过发送一个每个Unix程序员都熟悉的信号来处理异常,第二种情况下,内核执行恢复异常需要的所有步骤,例如缺页异常。

中断信号提供了一种特殊的方式,使处理器转而去运行正常的控制流之外的代码。当一个中断信号到达时,CPU必须停止它当前正在做的事情,保留上下文2,并切换产生中断后的一个空间。

虽然进程切换和中断都会导致内核保存上下文并且切换到另一空间,但中断处理程序和进程切换有一个明显的差异,由中断或异常处理程序执行的代码不是一个进程,更确切的说,它是一个内核执行路径,代表中断发生时正在运行的进程执行。作为一个内核控制路径,中断处理程序要比一个进程更轻量。

中断处理是由内核执行的最敏感的任务之一,因此它必须满足下面的约束:

当内核正打算去完成一些别的事情时,中断会随时到来。因此,内核的目标就是让中断尽可能快的处理完,尽其所能把更多的处理向后推迟。例如一个数据块已经到达了网线,当硬件中断内核时,内核只简单的标志数据到来了,让处理器恢复到它以前的运行状态,其余的处理稍后再进行。因此,内核响应中断后需要进行的操作氛围两部分,关键而紧急的部分内核立即执行,其他的推迟的部分内核随后会执行。

因为中断随时到来,所以内核可能正在处理其中一个中断的时候,另一个中断又会到来,应该尽可能多的允许这样的情况发生,因为这能维持更多的I/O设备处于忙状态,提高I/O设备的吞吐量。因此中断处理程序必须便写成使相应的内核控制路径能以嵌套的方式执行。当最后一个内核控制路径终止时,内核必须能恢复被中断执行的进程。

尽管内核在处理前一个中断时可以接受一个新的中断,但在内核代码中还是存在一些临界区,在临界区中,中断必须被禁止。必须尽可能的限制这样的临界区,因为根据以前的要求,内核,尤其时中断处理程序,应该在大部分时间内以开中断的方式运行。

Intel文档把中断和异常分为以下几类:

中断

  1. 可屏蔽中断,I/O设备发出的所有中断请求(IRQ)都产生可屏蔽中断,一个屏蔽的中断只要还是屏蔽的,控制单元就可以忽略它。
  2. 非屏蔽中断,有一些危险的事件才能引起非屏蔽中断,例如硬件故障,非屏蔽中断总是由CPU辨认。

异常

当CPU执行指令时探测到一个异常,会产生一个处理器探测异常(processor-detected exception),可以进一步区分,这取决于CPU控制单元产生异常时保存在内核堆栈eip寄存器的值。

  1. 故障(fault),通常可以纠正,一旦纠正,程序就可以重新开始,保存在eip寄存器中的值是引起故障的指令地址。
  2. 陷阱(trap)在陷阱指令执行后立即报告,内核把控制权烦给程序后就可以继续它的执行而不失连续性。保存在eip中的值是一个随后要执行的指令地址。陷阱的主要作用是为了调试程序。
  3. 异常中止(abort),发生一个严重的错误,控制单元出了问题,不能在eip寄存器中保存引起异常的指令所在的确切位置。异常中止用于报告严重的错误,例如硬件故障或系统表中无效的值或者不一致的值。这种异常会强制中止进程。
  4. 编程异常(programmed exception),在编程者发出的请求时发送,是由intint3指令触发的。

每个中断和异常是由0~255之间的一个数来标识的,Intel把这个8位无符号整数叫做一个向量(vector)。非屏蔽中断的向量和异常的向量是固定的,而可屏蔽中断的向量是可以通过对中断控制器的编程来改变。

  1. 产生异常的时候,CPU正在执行CS寄存器里的命令,出现中断一般都是应用程序引发的。

  2. 为了做到这一点,就要在内核态堆栈保存程序计数器和当前的值。


EOF