Signal
信号
信号是进程级异步事件通知机制。其目的是在目标进程的控制信息中标记某类事件发生。
信号机制的核心是三类控制信息:
| 信息 | 含义 |
|---|---|
| 待处理信号集 | 哪些信号已经到达,但还没有被处理 |
| 信号屏蔽字 | 哪些信号暂时被屏蔽,暂不投递给进程处理 |
| 信号处理动作表 | 每种信号采用默认处理、忽略,还是调用用户注册的处理函数 |
每种信号在目标进程 PCB 中表示为 1 bit:某位为 1 表示该类信号处于待处理状态。
一次典型信号处理过程:
- 信号产生。来源可能是终端输入、定时器、异常、I/O 状态变化,或其他进程请求发送信号。
- 内核记录信号。内核在目标进程的待处理信号集中设置对应位。
- 检查屏蔽字。若该信号被屏蔽,暂不处理;若未屏蔽,等待合适时机投递。
- 返回用户态前检查。进程因系统调用、异常、中断等原因进入内核态后,内核在返回用户态前检查是否有未屏蔽的待处理信号。
- 执行处理动作。内核根据该信号的处理动作表,执行默认动作、忽略,或安排用户处理函数运行。
- 处理结束后继续。若信号没有终止进程,处理完成后回到原进程的正常执行流。
为什么返回用户态前检查信号
信号处理需要内核介入,但用户自定义处理函数属于用户程序逻辑。进程进入内核态后,内核正好有机会检查待处理信号,并在返回用户态时把控制流切到用户注册的处理函数;处理函数返回后,再恢复到原本应继续执行的位置。
Linux 中用 kill、pkill 发送信号的命令用法见 Linux Signals。
信号和异常/中断
信号可以作为异常和中断处理之后的用户态通知方式。
| 来源 | 内核处理 | 可能转化出的信号 |
|---|---|---|
| 终端产生中断事件 | 终端驱动和内核处理控制字符 | SIGINT |
| 定时器到期 | 内核处理定时器中断或定时事件 | SIGALRM |
| 子进程退出 | 内核更新子进程状态,通知父进程 | SIGCHLD |
| 用户程序访问非法地址 | CPU 触发异常,内核判断无法继续正常执行 | SIGSEGV |
| 算术异常 | CPU 触发异常,内核定位到当前进程 | SIGFPE |
异常/中断首先让 CPU 转入内核态,由内核完成硬件相关或系统级处理。若这个事件需要通知某个用户进程,内核可以在该进程的待处理信号集中设置对应信号。之后,当该进程准备回到用户态时,信号机制再负责把这个事件交给进程处理。
异常与中断的基本机制见 Exception-And-Interrupt-Brief 和 Exception-And-Interrupt-Handling。
信号不是信号量
信号用于异步通知事件,例如终止、子进程退出。信号量用于同步、互斥或资源计数,例如缓冲区是否有空位、临界区是否可进入。二者名字相近,但用途完全不同。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Elian's blog page!