4

我发现以下代码在 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 没有说清楚。

4

2 回答 2

1

sigwait显然没有指定阻止任何信号。如果它在 MacOS X 上这样做,这似乎是一个错误。

于 2019-11-25T22:46:16.310 回答
1

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

我发现这是规范(IEEE Std 1003.1-2017)的合理实现,它要求sigwait(set, &s) 暂停调用线程,直到集合中的至少一个信号变为未决。

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

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

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

于 2019-11-26T14:56:02.367 回答