(二十二)异常和中断
一、异常的来源和应用
程序运行并不总是正常的,总有一些异常情况出现,这些异常有的来自硬件,称为硬件异常,有些来自软件称为软件异常。异常的发生和捕捉由硬件完成,而异常的处理却是由软件来完成。计算机会为每一种可能发生的异常设定一个异常编码,也可以称之为中断向量。异常的发生通常是由于CPU检测到了一个异常信号,这些信号也可称之为事件,CPU检测到异常信号时也就可以获取到异常信号所对应的异常编码。
有一些异常编码是定义在软件中的,如IO异常的就被定义在操作系统中,而加法溢出这种异常就被定义在CPU中。
异常信号被检测到以后,CPU就需要处理这些异常,而在内存中的一块区域保存着一个异常表(Exception Table),也叫做中断向量表,CPU在处理异常时,就会先保存程序执行现场,就是把寄存器保存到程序栈中,然后在异常标中查找到异常编码对应的异常处理程序,然后开始执行异常处理程序。
二、异常的分类
计算机执行中发生的异常一般可以分为以下几种:
(一)中断:通常由外部输入产生,发生时程序执行暂停一会,处理完成后继续执行下一条指令。
(二)陷进:由程序自身触发,发生时程序执行暂停一会,处理完成后继续执行下一条指令。程序断点调试、用户态切换内核态都属于它的应用
(三)故障:执行过程中发生了加法溢出等异常,处理完成继续当前指令的执行。
(四)中止:发生了程序无法处理的异常,只能退出程序执行。
尽管中断、陷阱、故障三种异常的产生来源不尽相同,但是其处理流程都是:保存现场、异常代码查询、异常处理程序调用。
三、异常处理
异常处理时,先保存当前程序执行的现场,然后在切换到执行异常处理代码,比起函数调用的先“将当前函数压栈,再切换执行被调用函数”更复杂,主要有以下区别:
- 异常处理除了本来的程序压栈工作外还需要将寄存器压栈
- 陷阱这样的异常,涉及用户态和内核态的切换,因此需要压入内核栈
- 故障这样的异常,处理程序执行完成之后,不是接着执行下一条指令,而是继续执行当前指令。
综上,异常的处理过程不是像函数调用一样的压栈、弹栈,而是更像两个进程在共享CPU,因此需要保存现场,切换上下文。