Linux系统 异常控制流
前言
下面内容大部分来自《深入理解计算机系统》(CSAPP)一书第八章异常控制流,更深入了解建议阅读此书第八章,推荐阅读《UNIX高级环境编程》。
异常控制流(Exception Control Flow, ECF) 是计算机系统中用来处理非正常情况的一种控制流方式。它允许程序在遇到错误或异常事件时,从正常的程序执行路径中跳出,执行特殊的处理逻辑,然后恢复正常流程或者终止程序。这种机制在操作系统、编程语言和硬件层面都有广泛应用。
异常
异常是异常控制流的一种形式,它一部分由硬件实现,一部分由操作系统实现。因为它们有一部分是由硬件实现的,所以具体细节将随系统的不同而有所不同。然而,对于每个系统而言,基本的思想都是相同的。
异常(exception)就是控制流中的突变,用来响应处理器状态中的某些变化。
在任何情况下,当处理器检测到有事件发生时,它就会通过一张叫做异常表(exception table)的跳转表,进行一个间接过程调用(异常),到一个专门设计用来处理这类事件的操作系统子程序(异常处理程序(exception handler)).当异常处理程序完成处理后,根据引起异常的事件的类型,会发生以下 3 种情况中的一种:
- 处理程序将控制返回给当前指令Icurr,即当事件发生时正在执行的指令。
- 处理程序将控制返回给 Inext ,如果没有发生异常将会执行的下一条指令。
- 处理程序终止被中断的程序。
异常类别
类别 | 原因 | 异步/同步 | 返回行为 |
---|---|---|---|
中断 | 来自 I/O 设备的信号 | 异步 | 总是返回到下一条指令 |
陷阱 | 有意的异常 | 同步 | 总是返回到下一条指令 |
故障 | 潜在可恢复的错误 | 同步 | 可能返回到当前指令 |
终止 | 不可恢复的错误 | 同步 | 不会返回 |
1. 中断(interrupt)
中断是一种由外部硬件设备发出的异步信号,用于引起 CPU 暂停当前执行的程序,去处理外部事件。中断机制的核心在于提供一种高效的方式来响应外部设备的请求,而不需要程序主动轮询设备的状态。
2. 陷阱和系统调用(trap)
陷阱是一种由程序主动触发的同步异常,用于请求操作系统的服务(例如系统调用)或进入调试模式。陷阱的目的是通过特定指令让程序安全地从用户模式切换到内核模式,从而执行特权操作。
3. 故障(fault)
故障是一种由程序触发的同步异常,表示某些潜在错误需要立即处理。故障的处理机制允许操作系统尝试修复问题,使程序可以恢复并继续执行。
4. 终止(abort)
终止是一种不可恢复的异常,通常由硬件或系统检测到的致命错误触发。这种错误表示程序或系统的状态已经严重损坏,无法继续运行。
异常控制流(ECF)发生在计算机系统的各个层次,是计算机系统中提供并发的基本机制。
在硬件层,异常是由处理器中的事件触发的控制流中的突变。控制流传递给一个软件处理程序,该处理程序进行一些处理,然后返回控制给被中断的控制流。
有四种不同类型的异常:中断、故障、终止和陷阱。当一个外部 I/O 设备(例如定时器芯片或者磁盘控制器)设置了处理器芯片上的中断管脚时,(对于任意指令)中断会异步地发生。控制返回到故障指令后面的那条指令。一条指令的执行可能导致故障和终止同步发生。故障处理程序会重新启动故障指令,而终止处理程序从不将控制返回给被中断的流。最后,陷阱就像是用来实现向应用提供到操作系统代码的受控的人口点的系统调用的函数调用。
在操作系统层,内核用 ECF 提供进程的基本概念。进程提供给应用两个重要的抽象:
逻辑控制流,它提供给每个程序一个假象,好像它是在独占地使用处理器;
私有地址空间,它提供给每个程序一个假象,好像它是在独占地使用主存。
在操作系统和应用程序之间的接口处,应用程序可以创建子进程,等待它们的子进程停止或者终止,运行新的程序,以及捕获来自其他进程的信号。信号处理的语义是微妙的,并且随系统不同而不同。然而,在与 Posix 兼容的系统上存在着一些机制,允许程序清楚地指定期望的信号处理语义。
最后,在应用层,C 程序可以使用非本地跳转来规避正常的调用/返回栈规则,并且直接从一个函数分支到另一个函数。