异常控制流

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 是用户指定的一种异常。通常而言,用户态程序可能需要执行某些内核态的操作, readforkexecve 等等。 这类向内核请求的服务最终都会通过 syscall 指令引发 Trap,跳转到 exception handler,在其中解析参数,调用适当的内核程序,然后返回到下一条指令。

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

Fault

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

Abort

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