信号处理程序适用于所有信号。

5
如何使用signal(3)为在运行中的操作系统上的所有信号注册一个信号处理程序?
我的代码如下:
void sig_handler(int signum)
{
    printf("Received signal %d\n", signum);
}


int main()
{
    signal(ALL_SIGNALS_??, sig_handler);
    while (1) {
        sleep(1);
    };
    return 0;
}

3
for循环中,是从1到31? - Jakub M.
5
每个系统都有一个信号列表,可以在 /usr/include/signal.h 中查看。没有一个通用的宏可以代表所有信号。此外,有些信号是无法被捕获的,例如 SIGKILL - jim mcnamara
1
然后你应该检查你在哪个平台上...但我不认为你需要它们所有,SIGINT、SIGUSR1/2和一些其他的应该就足够了。顺便说一句,在/usr/include/bits/signum.h中,你可以找到所有这些信号及其描述。 - Tom
3
在信号处理程序中,你不能使用printf()函数(它是非重入的)。 - wildplasser
1
@R如果在信号处理程序内执行printf时有新的信号到来会发生什么?(提示:不好的事情)即使在这个简单的程序中,调用printf在信号处理程序中也是不安全的。 - William Pursell
显示剩余4条评论
2个回答

7

大多数系统都有一个宏NSIG_NSIG(前者在符合标准的模式下不可用,因为它违反了命名空间)定义在signal.h中,这样一个循环for (i=1; i<_NSIG; i++)将遍历所有信号。此外,在具有信号掩码的POSIX系统上,CHAR_BIT*sizeof(sigset_t)是您可以使用的信号数量的上限,如果既没有定义NSIG也没有定义_NSIG


但我不明白为什么不是 i = 0 而是 i = 1。根据上面链接中的解释,NSIG 的值既对应于定义的信号数量,也对应于 <最大信号编号> + 1,这意味着信号编号从 0 开始。我怀疑你的代码是有意这样写的,请给我一个解释好吗?(也许与 kill -0 是什么? 有关?) - ynn

3

信号处理程序需要处理可重入性问题和其他问题。实际上,掩盖信号并随时检索它们通常更方便。你可以使用以下方法屏蔽所有信号(除了 SIGSTOPSIGKILL,因为你无法处理它们):

sigset_t all_signals;
sigfillset(&all_signals);
sigprocmask(SIG_BLOCK, &all_signals, NULL);

如果您正在使用pthreads,代码会稍有不同。在每个线程中调用此函数,或者(最好的方式)在创建任何其他线程之前在主线程中调用:

sigset_t all_signals;
sigfillset(&all_signals);
pthread_sigmask(SIG_BLOCK, &all_signals, NULL);

完成后,您应该定期调用sigtimedwait(2),如下所示:

struct timespec no_time = {0, 0};
siginfo_t result;
int rc = sigtimedwait(&all_signals, &result, &no_time);

如果有一个信号在等待,有关其信息将被放置在result中,并且rc将是该信号的编号;如果没有,则rc将为-1,errno将是EAGAIN。如果您已经在调用select(2)/poll(2)(例如作为某些事件驱动系统的一部分),则可能希望创建一个signalfd(2)并将其附加到事件循环中。在这种情况下,您仍然需要像上面展示的那样屏蔽信号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接