Notes about signal in Linux
资料
信号是什么
例:
- 输入命令,在Shell下启动一个前台进程。
- 用户按下Ctrl-C,键盘输入产生一个硬件中断。
- 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行, CPU从用户态切换到内核态处理硬件中断。
- 终端驱动程序将Ctrl-C解释成一个
SIGINT
信号,记在该进程的PCB中(也可以说发送了一个SIGINT
信号给该进程)。 - 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信号,发现有一个
SIGINT
信号待处理,而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。
在这个例子中,由Ctrl-C产生的硬件中断就是一个信号。Ctrl+C产生的信号只能发送给前台进程,命令后加&就可放到后台运行。Shell可同时运行一个前台进程和任意多个后台进程,只有前台进程才能接受到像CTRL+C这种控制键产生的信号。
信号的种类
信号的产生
- 硬件产生
- 软件产生
信号的注册
信号注册实际上是一个位图和一个sigqueue队列。
信号的注销
信号阻塞
信号未决
实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
信号的处理方式
每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作。
信号的捕捉
条件: 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这就称为信号捕捉。
流程:
内核态返回用户态会调用do_signal
函数,两种情况:
- 无信号:
sys_return
函数,返回用户态 - 有信号:先处理信号,信号返回,再调用
do_signal
函数
例:
- 程序注册了
SIGQUIT
信号的处理函数sighandler。 - 当前正在执行main函数,这时发生中断或异常切换到内核态。
- 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。
- 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函数, sighandler和main函数之间不存在调用和被调用的关系,是两个独立的控制流程。
- sighandler函数返回后自动执行特殊的系统调用sig_return再次进入内核态。
- 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。
常用信号集操作函数
SIGCHLD信号
SIGKILL vs SIGTERM
Though both of these signals are used for killing a process, there are some differences between the two:
SIGTERM
gracefully kills the process whereasSIGKILL
kills the process immediately.SIGTERM
signal can be handled, ignored, and blocked, butSIGKILL
cannot be handled or blocked.SIGTERM
doesn’t kill the child processes.SIGKILL
kills the child processes as well.
参考资料: