# 8.5 信号
到目前为止对异常控制流的学习中,我们已经看到了硬件和软件是如何合作以提供基本的低层异常机制的。我们也看到了操作系统如何利用异常来支持进程上下文切换的异常控制流形式。在本节中,我们将研究一种更高层的软件形式的异常,称为 Linux 信号,它允许进程和内核中断其他进程。
一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件。比如,图 8-26 展示了 Linux 系统上支持的 30 种不同类型的信号。
每种信号类型都对应于某种系统事件。低层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。比如,如果一个进程试图除以 0,那么内核就发送给它一个 SIGFPE 信号(号码 8)。如果一个进程执行一条非法指令,那么内核就发送给它一个 SIGILL 信号(号码 4)。如果进程进行非法内存引用,内核就发送给它一个 SIGSEGV 信号(号码 11)。其他信号对应于内核或者其他用户进程中较高层的软件事件。比如,如果当进程在前台运行时,你键入 Ctrl+C(也就是同时按下 Ctrl 键和 C 键),那么内核就会发送一个 SIGINT 信号(号码 2)给这个前台进程组中的每个进程。一个进程可以通过向另一个进程发送一个 SIGKILL 信号(号码 9)强制终止它。当一个子进程终止或者停止时,内核会发送一个 SIGCHLD 信号(号码 17)给父进程。
| 序号 | 名称 | 默认行为 | 相应事件 |
|---|---|---|---|
| 1 | SIGHUP | 终止 | 终端线挂断 |
| 2 | SIGINT | 终止 | 来自键盘的中断 |
| 3 | SIGQUIT | 终止 | 来自键盘的退出 |
| 4 | SIGILL | 终止 | 非法指令 |
| 5 | SIGTRAP | 终止并转储内存① | 跟踪陷阱 |
| 6 | SIGABRT | 终止并转储内存① | 来自 abort 函数的终止信号 |
| 7 | SIGBUS | 终止 | 总线错误 |
| 8 | SIGFPE | 终止并转储内存① | 浮点异常 |
| 9 | SIGKILL | 终止② | 杀死程序 |
| 10 | SIGUSR1 | 终止 | 用户定义的信号 1 |
| 11 | SIGSEGV | 终止并转储内存① | 无效的内存引用(段故障) |
| 12 | SIGUSR2 | 终止 | 用户定义的信号 2 |
| 13 | SIGPIPE | 终止 | 向一个没有读用户的管道做写操作 |
| 14 | SIGALRM | 终止 | 来自 alarm 函数的定时器信号 |
| 15 | SIGTERM | 终止 | 软件终止信号 |
| 16 | SIGSTKFLT | 终止 | 协处理器上的栈故障 |
| 17 | SIGCHLD | 忽略 | 一个子进程停止或者终止 |
| 18 | SIGCONT | 忽略 | 继续进程如果该进程停止 |
| 19 | SIGSTOP | 停止直到下一个 SIGCONT② | 不是来自终端的停止信号 |
| 20 | SIGTSTP | 停止直到下一个 SIGCONT | 来自终端的停止信号 |
| 21 | SIGTTIN | 停止直到下一个 SIGCONT | 后台进程从终端读 |
| 22 | SIGTTOU | 停止直到下一个 SIGCONT | 后台进程向终端写 |
| 23 | SIGURG | 忽略 | 套接字上的紧急情况 |
| 24 | SIGXCPU | 终止 | CPU 时间限制超出 |
| 25 | SIGXFSZ | 终止 | 文件大小限制超出 |
| 26 | SIGVTALRM | 终止 | 虚拟定时器期满 |
| 27 | SIGPROF | 终止 | 剖析定时器期满 |
| 28 | SIGWINCH | 忽略 | 窗口大小变化 |
| 29 | SIGIO | 终止 | 在某个描述符上可执行 I/O 操作 |
| 30 | SIGPWR | 终止 | 电源故障 |
图 8-26 Linux 信号
注:
① 多年前,主存是用一种称为磁芯存储器(core memory)的技术来实现的。“转储内存”(dumping core)是一个历史术语,意思是把代码和数据内存段的映像写到磁盘上。
② 这个信号既不能被捕获,也不能被忽略。
(来源:man 7 signal。数据来自 Linux Foundation。)