【问题标题】:Does sigwait() behave differently in macOS and Linux?sigwait() 在 macOS 和 Linux 中的行为是否不同?
【发布时间】:2020-03-21 06:51:27
【问题描述】:

我发现以下代码在 macOS 和 Linux 中的工作方式不同:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>

void catcher( int sig ) {
    printf( "Signal catcher called for signal %d\n", sig );
}

int main( int argc, char *argv[] ) 
{
    struct sigaction sigact;
    sigset_t waitset;
    int sig;
    int result = 0;

    sigemptyset( &sigact.sa_mask );
    sigact.sa_flags = 0;
    sigact.sa_handler = catcher;

    sigaction( SIGINT, &sigact, NULL );

    sigemptyset( &waitset );
    sigaddset( &waitset, SIGHUP);

    result = sigwait(&waitset, &sig) ;
    if(result == 0)
    {
        printf( "sigwait() returned for signal %d\n", sig );
    }
}

当在 macOS 上运行并将 SIGINT 发送到进程时,其处理程序仅在发送 SIGHUP 后执行(从而导致 sigwait() 返回)。换句话说,它看起来 sigwait() 在其等待期间阻塞了其等待掩码之外的所有信号。当同一个程序在 Linux 上运行时,只要将 SIGINT 发送到进程,就会传递 SIGINT,即运行处理程序。因此它在 Linux 中看起来 sigwait() 不会阻塞其等待掩码之外的信号。 哪个是标准行为? SUSv3 没有说清楚。

【问题讨论】:

  • 我可以请您在调用sigwait 之前先#include &lt;signal.h&gt; 和SIG_BLOCK 该SIGINT 吗? (两者都不会从您识别的陌生感中减去。)
  • 显然signal.h 包含(该行只是在副本中滑落,否则不会编译)。添加 SIGINT 块可以在 macOS 中按预期工作。也就是说,SIGINT 阻塞,在 SIGHUP 之后,程序定期退出。
  • 对不起,我打错了后半部分——我的意思是 SIG_BLOCK 那个 SIGHUP。对非阻塞信号使用sigwait 是明确未定义的。
  • 我不确定是否理解:SUS 说“set 定义的信号在调用 sigwait() 时应已被阻塞;否则,行为未定义。”这里提出的问题是信号 not 在传递给 sigwait() 的集合中。

标签: c macos linux-kernel signals sus


【解决方案1】:

sigwaitclearly not specified to block any signals。如果它在 MacOS X 上这样做,这似乎是一个错误。

【讨论】:

  • 这也是我的印象。谢谢
  • 从问题的 cmets 看来,如果您没有阻止您正在等待的信号,则该行为实际上是未定义的。所以理论上你有可能打到这个UB。但没有必要阻止您不等待的信号。
  • @R..,经过反思和测试,我认为 OS X 不是阻塞,而是暂停。原因见我的回答。
  • @pilcrow:这不是它的工作方式。禁止 EINTR 并不意味着在函数执行时信号被延迟。只是它在信号处理程序返回后继续运行。这一切都在 XSH 的信号部分中指定,在各个函数之前。
【解决方案2】:

OS X 不会阻止无关信号,而是暂停进程 à la SIGSTOP。

我发现这是the specification(IEEE Std 1003.1-2017)的合理实现,它要求sigwait(set, &amp;s) 暂停调用线程直到set中至少有一个信号em> 处于待处理状态。

就像真正的 STOP 一样,OS X 将不可阻止的 SIGKILL 保持在海湾,直到进程恢复。 ps 可以看到 STOP 和 sigwait 之间的区别,当然每个进程的恢复过程都不同(CONT 与 set),但它们本质上是相同的进程状态。

另一方面,在我看来,Linux 似乎假装sigwait 是可中断的,而且用户定义的操作是通过 SA_RESTART 安装的。调用用户定义的处理程序,并立即执行 KILL。在我看来,这种行为更有用,但不是规范——如果线程可以执行用户定义的信号处理程序,它就不会被挂起。

当然,这种情况有点做作,因为sigwait 在设计时确实考虑到了多线程程序。

【讨论】:

  • 这不是它的工作原理。禁止 EINTR 并不意味着在函数执行时信号被延迟。只是它在信号处理程序返回后继续运行。这一切都在 XSH 的信号部分中指定,在各个函数之前。
  • 如果线程可以执行用户定义的信号处理程序,它就不会被挂起。 不幸的是,POSIX 没有提供“挂起”的定义。见3. Definitions
猜你喜欢
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
相关资源
最近更新 更多