当多个信号到达一个过程时,处理信号的过程之间的顺序是什么?

时间:2018-06-01 02:52:43

标签: linux algorithm data-structures signals

当多个信号到达某个过程时,处理信号的过程之间的顺序是什么?

使用什么数据结构来存储已到达流程但尚未交付的信号?

例如,来自APUE

  

由于进程组在进行父节点化时是孤立的,因此POSIX.1要求发送停止的新孤立进程组中的每个进程(如我们的子进程)发送挂起信号(SIGHUP)后跟继续信号(SIGCONT)

     

这会导致孩子继续,处理挂断信号后。该   挂起信号的默认动作是终止进程,所以我们必须这样做   提供信号处理程序来捕获信号。因此,我们期待printf in   sig_hup函数出现在pr_ids函数的printf之前。

正如https://stackoverflow.com/a/17769300/156458所说

  

在孩子的执行恢复之前,无法交付SIGHUP。   当进程停止时,除了之外,所有信号传递都将暂停   SIGCONT和SIGKILL。

     

所以,SIGHUP确实到达第一个,但是直到才能处理   SIGCONT唤醒了流程执行。

SIGHUP在SIGCONT停止进程之前到达。在SIGCONT可以的情况下,SIGHUP不能被提供。

在SIGHUP之前或之后处理SIGCONT?第一个引用似乎在"之后说"而第二个引用似乎在"之前说""通过"直到"。

如果"之前":

  • 如何安排SIGCONT超越SIGHUP交付?

  • 当SIGCONF在被提交之前跳转时,如何不丢弃SIGHUP?

以上是基于某些数据结构实现的,例如FIFO队列还是FILO堆栈?

感谢。

3 个答案:

答案 0 :(得分:3)

这种情况可能因不同的实现和POSIX实时信号的引入而混淆。 http://man7.org/linux/man-pages/man7/signal.7.html说实时信号与旧式信号不同

实时信号以保证的顺序发送。多            按顺序传送相同类型的实时信号            他们被送了。如果向a发送不同的实时信号            过程中,它们从最低编号开始交付            信号。 (即,低编号信号具有最高优先级。)            相反,如果有多个标准信号待处理,            它们的交付顺序是未指定的。

由Bach的“Unix操作系统设计”中描述的旧式信号(在引入POSIX实时信号之前)。

为了向进程发送信号,内核在进程表条目的信号字段中设置一个位,对应于接收到的信号类型。 ...当进程从内核模式返回到用户模式时以及当它以适当低的信令优先级离开睡眠状态时,内核会检查是否收到信号。

您可以在https://github.com/torvalds/linux/blob/master/include/linux/sched.h看到一些当前的Linux数据结构。看看这个我怀疑老式位图已经消失了,并且位图和链表的组合用于处理旧样式和POSIX实时信号,但我还没有通过足够的代码来确定这一点

答案 1 :(得分:3)

添加到mcdowella的回复:

1)“信号处理”的细节因平台而异[/ p>

2)在Linux的特定情况下:

  

http://man7.org/linux/man-pages/man7/signal.7.html

     

Linux支持POSIX可靠信号(以下简称“标准版”)          信号“)和POSIX实时信号。

3)另见:

答案 2 :(得分:1)

SIGCONT具有特殊的语义。

无论SIGCONT是被捕获,被忽略还是具有默认处置,其生成都将清除所有待处理的停止信号并继续执行已停止的进程。 [IEEE Std 1003.1-2017]同样,这种恢复在发生任何其他信号之前发生,甚至在调用SIGCONT的处理程序(如果有的话)之前发生。

(这种特殊的“无意义”语义是有道理的。为了使进程执行信号处理程序,进程本身必须执行。)

POSIX比APUE更清晰,说"[t]he default action for SIGCONT is to resume execution at the point where the process was stopped, after first handling any pending unblocked signals."

正如其他人所提到的,交付待处理信号的实际顺序是特定于实现的。至少Linux以递增的数字顺序提供基本的UNIX信号。

为了演示这一切,请考虑以下代码。它停止一个进程,然后向它发送几个信号,然后继续它,为所有捕获信号安装了处理程序,这样我们就可以看到在下面处理的是什么:

#define _POSIX_SOURCE
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

static int signals[] = { SIGSTOP, SIGURG, SIGUSR1, SIGHUP, SIGCONT, 0 };

static void
handler(int signo) {
  // XXX not async-signal-safe
  printf("<signal %d>\n", signo);
}

int
main(int argc, char **argv) {
  int *sig = signals;
  struct sigaction sa = { .sa_flags = 0, .sa_handler = handler };

  sigfillset(&sa.sa_mask);

  sig++; // can't catch SIGSTOP
  while (*sig) {
    sigaction(*sig, &sa, NULL); // XXX error check
    sig++;
  }

  if (fork() == 0) { // XXX error check
    sleep(2);        // faux synchronization - let parent pause()

    sig = signals;
    while (*sig) {
      printf("sending signal %d\n", *sig);
      kill(getppid(), *sig);
      sig++;
    }
    exit(0);
  }

  pause();

  return 0;
}

对我来说,打印

sending signal 19
sending signal 23
sending signal 10
sending signal 1
sending signal 18
<signal 1>
<signal 10>
<signal 18>
<signal 23>