本文将mark下Linux的signal相关notes。

资料

一篇文章彻底搞定信号

信号是什么

例:

  1. 输入命令,在Shell下启动一个前台进程。
  2. 用户按下Ctrl-C,键盘输入产生一个硬件中断。
  3. 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行, CPU从用户态切换到内核态处理硬件中断。
  4. 终端驱动程序将Ctrl-C解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了一个SIGINT信号给该进程)。
  5. 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。

在这个例子中,由Ctrl-C产生的硬件中断就是一个信号。Ctrl+C产生的信号只能发送给前台进程,命令后加&就可放到后台运行。Shell可同时运行一个前台进程和任意多个后台进程,只有前台进程才能接受到像CTRL+C这种控制键产生的信号。

信号的种类

信号的产生

  • 硬件产生
  • 软件产生

信号的注册

信号注册实际上是一个位图和一个sigqueue队列。

信号的注销

信号阻塞

信号未决

实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

信号的处理方式

每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作。

信号的捕捉

条件: 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这就称为信号捕捉。

流程:

内核态返回用户态会调用do_signal函数,两种情况:

  1. 无信号:sys_return函数,返回用户态
  2. 有信号:先处理信号,信号返回,再调用do_signal函数

例:

  1. 程序注册了SIGQUIT信号的处理函数sighandler。
  2. 当前正在执行main函数,这时发生中断或异常切换到内核态。
  3. 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。
  4. 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函数, sighandler和main函数之间不存在调用和被调用的关系,是两个独立的控制流程。
  5. sighandler函数返回后自动执行特殊的系统调用sig_return再次进入内核态。
  6. 如果没有新的信号要递达,这次再返回用户态就是恢复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 whereas SIGKILL kills the process immediately.
  • SIGTERM signal can be handled, ignored, and blocked, but SIGKILL cannot be handled or blocked.
  • SIGTERM doesn’t kill the child processes. SIGKILL kills the child processes as well.


参考资料:

  1. man signal
  2. A list of signals and what they mean
  3. SIGTERM vs SIGKILL: What’s the Difference?