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:
SIGTERMgracefully kills the process whereasSIGKILLkills the process immediately.SIGTERMsignal can be handled, ignored, and blocked, butSIGKILLcannot be handled or blocked.SIGTERMdoesn’t kill the child processes.SIGKILLkills the child processes as well.

参考资料:
