中断的作用
CPU上主要运行两种程序:用户程序和内核程序,这一点在上一章已详细讲解,此处不再赘述。而中断的核心作用,就是让操作系统重新夺回CPU的控制权,如果没有中断机制,一旦某个程序获得CPU执行权,就会一直占用CPU资源,操作系统无法介入调度其他程序,整个系统会陷入“卡死”状态,只能执行这一个程序,无法响应任何其他操作。
如此一来,操作系统的核心特性“并发性”就无从谈起。因此,我们可说没有中断,就没有真正意义上的操作系统。
中断的类型
中断可以根据信号的来源不同分为由CPU内部产生的内部中断和由外部设备产生的外部中断两大类,内部中断常常与当前执行的指令有关,比如上一章提到的用户态下尝试执行特权指令或是除零错误等非法操作(所以内部中断常常被称为异常),外部中断则是由外部设备发出的信号,比如键盘输入、鼠标点击、网络数据到达等,这些事件都需要操作系统及时响应,所以外部设备会通过中断向CPU发送信号,通知它有新的事件需要处理。
有时候应用程序想请求内核的服务,此时会执行一条特殊的指令,叫做陷入指令,这条指令也会触发一个中断,切换到内核态,由操作系统的内核程序来处理这个请求,这是一种特殊的中断,我们之前提到过的系统调用就是通过这种方式实现的。
中断的基本原理
当一个中断发生时,不同的中断信号需要不同的处理程序来处理,操作系统会为每种类型的中断设置一个中断向量表,这个表里存储了每个中断类型对应的处理程序的地址,当中断发生时,CPU会根据中断类型查找这个表,找到对应的处理程序地址,然后跳转到那个地址执行相应的处理程序,这样就能够及时响应各种不同的事件和请求了
flowchart LR
INT["中断信号发生
(含中断类型编号)"] --> CPU["CPU
保存当前程序现场
切换到内核态"]
CPU -->|"用中断类型编号
查表"| IVT
subgraph IVT["中断向量表(内存)"]
direction LR
E0["类型0 → 地址 0x1000
除零异常处理"]
E1["类型1 → 地址 0x2000
键盘中断处理"]
E2["类型2 → 地址 0x3000
系统调用处理"]
EN["…"]
end
IVT -->|"取出对应地址"| JMP["跳转到处理程序地址"]
JMP --> HANDLER["执行中断处理程序"]
HANDLER -->|"处理完成
恢复现场"| RET["返回用户态
继续执行原程序"]