Linux信号及工作原理

什么是信号

信号可以理解为软件中断,是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是差不多的。信号是异步的,一个进程不必通过任何操作来等待信号的到达。信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。

谁来产生信号

信号事件的发生有两个来源:

  • 硬件来源,比如我们按下ctrl+c,会产生SIGINT信号。
  • 软件来源,比如我们调用alarm函数来产生SIGALRM信号。

常用信号

Linux信号的编号是从1-64,其中32和33空缺,没有对应的信号。通过kill -l 可查看所有的信号。

1~31之间的信号叫做不可靠信号, 信号可能会丢失, 也叫做非实时信号。

34~64之间的信号叫做可靠信号, 信号不会丢失, 也叫做实时信号。

信号响应方式

信号有如下三种响应方式:

  1. 忽略信号,即对信号不做任何处理,但是有两个信号不能忽略,即 SIGKILL 及 SIGSTOP。
  2. 捕捉信号,定义信号处理函数,当信号发生时,执行相应的自定义处理函数。
  3. 执行缺省操作,Linux 对每种信号都规定了默认操作。

信号处理过程

信号处理的大致流程如下:

信号产生 -> 信号注册 -> 信号在进程中注销 -> 信号处理函数执行完毕

我们主要讲一下“信号注册” 和“信号在进程中注销”。其他两个都比较好理解。

信号注册指的是在目标进程中注册,该目标进程中有未决信号的信息。啥叫未决信号呢,实际执行信号的处理动作称为信号递达,信号从产生到递达之间的状态,称为信号未决。

先来看一下对应的结构体:


struct sigpending{
  //未决信号链的头部与尾部
    struct sigqueue *head, *tail;
  //未决信号集
    sigset_t signal;
};

struct sigqueue{
    struct sigqueue *next;
  //信号所携带的信息
    siginfo_t info;
}

信号注册的过程就是将信号值加入到未决信号集siginfo_t中,将信号所携带的信息加入到未决信号链的某一个sigqueue中去。

因此,对于可靠的信号,可能存在多个未决信号的sigqueue结构,对于每次信号到来都会注册。而不可靠信号只注册一次,只有一个sigqueue结构。

只要信号在进程的未决信号集中,表明进程已经知道这些信号了,还没来得及处理,或者是这些信号被阻塞。

信号在进程中注销是指进程已经接收到信号了,会在链表中移除。在进程的执行过程中,每次从系统调用或中断返回用户空间的时候,都会检查是否有信号没有被处理。如果这些信号没有被阻塞,那么就调用相应的信号处理函数来处理这些信号。可靠信号和不可靠信号的处理有所不同:

不可靠信号:由于不可靠信号在未决信号链中只有一个sigqueue结构,因此将它删除的同时,也会将信号从未决信号集中删除。

可靠信号:由于可靠信号在未决信号链中可能有多个sigqueue结构,如果只有一个,也将信号从未决信号集中删除掉。如果有多个则不从未决信号集中删除信号,注销完毕。

下一篇
« Prev Post
上一篇
Next Post »