XOPEN_SOURCE和信号处理

yas*_*sar 8 c linux standards signals

在下面的程序中,如果我取消注释_XOPEN_SOURCE行,我的程序在我点击时终止C-c,相同的程序不会终止如果我不评论该行.任何人都知道_XOPEN_SOURCE影响信号处理的方式有哪些?我在linux上使用gcc(4.6.3)和glibc(2.15).

/* #define _XOPEN_SOURCE 700 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

typedef void (*sighandler_t)(int);

void handle_signal(int signo)
{
    printf("\n[MY_SHELL] ");
    fflush(stdout);
}

int main()
{
    int c;
    signal(SIGINT, SIG_IGN);
    signal(SIGINT, handle_signal);
    printf("[MY_SHELL] ");
    while ((c = getchar()) != EOF) {
        if (c == '\n')
            printf("[MY_SHELL] ");
    }
    printf("\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

caf*_*caf 4

问题是,signal()在安装信号处理函数时,该函数可以有两种不同形式的行为:

  • System V 语义,其中信号处理程序是“一次性”的——也就是说,在调用信号处理函数之后,信号的处置被重置为SIG_DFL——并且被信号中断的系统调用不会重新启动;或者
  • BSD 语义,其中信号处理程序在信号触发时不会重置,信号在信号处理程序执行时被阻塞,并且大多数中断的系统调用会自动重新启动。

在使用 glibc 的 Linux 上,如果已定义,您将获得 BSD 语义_BSD_SOURCE;如果未定义,您将获得 System V 语义。该_BSD_SOURCE宏是默认定义的,但如果您定义_XOPEN_SOURCE(或其他一些宏,例如_POSIX_SOURCE_SVID_SOURCE),则此默认定义将被抑制。

在 System V 语义下,如果read()底层系统调用getchar()被中断,SIGINT那么getchar()将返回EOFerrno设置为EINTR(这将导致您的程序正常退出)。此外,在第一个信号之后,SIGINT该信号的处理将重置为默认值,并且默认操作是SIGINT终止进程(因此,即使您的程序在第一个信号中幸存下来SIGINT,第二个信号也会导致它异常退出)。

解决方案是根本不使用signal()安装信号处理函数;相反,您应该使用sigaction(),它是可移植的 - 它在任何地方都给出相同的语义。设置sa_flagsSA_RESTARTsigaction()它将给出 BSD 语义,这就是您想要的。