异常控制流

Falldio宜昌

我之前在看小林 coding 图解系统的时候,对中断的概念云里雾里, 后来看了 CSAPP 的有关章节,才对这类事件处理机制有了比较系统的理解。这篇 post 概括了包括中断在内的四种异常,作为对这类内容的总结。

OS 在运行过程中需要对各类突发情况做出及时反应,比如定时器事件、网络数据包到达、内存缺页等。

通常情况下,OS 需要从当前的逻辑流程中跳出,转移到这类事件的处理程序,这种突然的跳转被称为异常控制流(Exceptional Control Flow,ECF)。

异常(exception)由软硬件结合实现。通常而言,OS 在正常执行指令时,若出现某些需要立刻处理的事件,则通过异常表(exception table)跳转到特定异常处理程序(exception handler)。当处理完成后,根据异常类型,OS 可能会进入以下几种状态:

  1. OS 重新执行异常发生时的指令;
  2. OS 跳过异常发生时的指令,直接进入下一条指令;
  3. OS 终止原本的程序。

异常可以分为四类,这里我直接 copy CSAPP 中的异常分类表:

ClassCauseAsync/SyncReturn behavior
InterruptSignal from I/O deviceAsyncAlways returns to next instruction
TrapIntentional exceptionSyncAlways returns to next instruction
FaultPotentially recoverable errorSyncMight return to current instruction
AbortNonrecoverable errorSyncNever returns

Interrupt ​

Interrupt 是由硬件设备触发的,如定时器、硬盘、网络适配器等,而不是特定的指令,故为异步机制。 OS 将会根据硬件设备放到系统总线的异常号,调用对应的 interrupt handler 程序。 interrupt handler 返回后,原程序将继续执行下一条指令,对这种异常没有任何感知。

Trap ​

Trap 这个术语在中文中被翻译为 “陷入”、“陷阱”,大概因为词性会根据上下文变化,所以总感觉怪怪的。 Trap 是用户指定的一种异常。通常而言,用户态程序可能需要执行某些内核态的操作, read 、 fork 、 execve 等等。 这类向内核请求的服务最终都会通过 syscall 指令引发 Trap,跳转到 exception handler,在其中解析参数,调用适当的内核程序,然后返回到下一条指令。

对用户而言,他只是调用了某个函数而已,it makes no difference。

Fault ​

Fault 的处理比上述两种异常复杂一点,由某些错误的状况引起,比如缺页异常 page fault、段异常 segmentation fault 等。 OS 不确定这类异常能否被 exception handler 修正,如果可以,则返回到当前指令重新执行, 否则则触发 Abort。

Abort ​

Abort 是不可恢复的致命错误,比如硬件损坏等,exception handler 将控制返回给 abort 例程,最终终止该程序。