奇怪的sigaction()和getline()交互

时间:2013-10-02 15:38:07

标签: c signals getline signal-handling

我有一个使用sigaction设置的信号处理程序,如下所示:

struct sigaction act, oldact;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = sig_handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGALRM);
sigaddset(&act.sa_mask, SIGINT);
sigaddset(&act.sa_mask, SIGTERM);
sigaddset(&act.sa_mask, SIGTSTP);
sigaction(SIGALRM, &act, &oldact);
sigaction(SIGINT, &act, &oldact);
sigaction(SIGTERM, &act, &oldact);
sigaction(SIGTSTP, &act, &oldact);
act.sa_flags = 0;

在此之后,我运行一个for循环来收集输入并将其打印出来(基本上就像猫一样)。

char *linebuf = NULL;
size_t n = 0;
int len;
while(1){
    len = getline(&linebuf, &n, stdin);
    if(len>0){
        printf("%s", linebuf);
    }
}

但是,一旦我从处理信号返回,getline()不再阻止输入,而是在-1设置为errno时始终返回EINTR系统调用。我显然打算打断getline(),但是如何重置它以便我可以继续读取输入?

有一些类似的问题并没有真正解决我的问题,但它可能会帮助您更好地理解问题。 1 2

另一个有趣的消息是,当我使用signal()进行信号处理时,我没有遇到此问题,但我更改为sigaction(),因为它符合POSIX标准。

2 个答案:

答案 0 :(得分:4)

您链接的其中一个问题实际上有您的答案。但首先,有几个参考文献。请注意,getline在内部使用其他功能(可能是read)。

来自read的手册页:

  

如果read()在读取任何数据之前被信号中断,它将返回-1并将errno设置为[EINTR]。

     

...

     

...还有一个附加函数select(),其目的是暂停,直到在指定的文件描述符上检测到指定的活动(要读取的数据,要写入的空间等)。在为那些系统编写的应用程序中,通常在read()之前使用的应用程序(例如键盘输入)中使用,因为需要中断I / O.

来自select的手册页:

  

pselect()函数应检查文件描述符集...以查看它们的某些描述符是否已准备好进行读取,是否已准备好写入,或者是否有待处理的异常条件。

因此,您可以使用select来了解何时开始阅读是安全的。但是,这仍然不会阻止read稍后中断。 (我刚才这样说是为了你的信息)。

要实际清除流的错误标记,将this answer作为一个链接的问题状态(尽管在C ++中),您需要使用clearerr函数清除任何错误标记。流。请注意,手册页(以及C标准)没有具体说明它也清除了“中断”标志,但这仅仅是因为它超出了C的范围,并且属于POSIX领域。


作为旁注,我想说,请不要使用memset来清除结构。 C有一个非常好的方法:

struct sigaction act = {0};

或者如果你想要迂腐,因为struct sigaction的第一个元素可能是另一个结构或数组,你可以分配给它的一个强制字段:

struct sigaction act = { .sa_handler = NULL };

答案 1 :(得分:4)

答案非常晚,但我会分享一些我最近学到的东西。在sigaction结构中将sa_flags设置为0时,在获取信号时清除了读取的默认行为。使用旧的signal()方法时,将保留此默认行为。要在您的情况下恢复,您必须设置sa_flags = SA_RESTART。但是在这种情况下,将调用信号处理程序,如果getline不在读取的中间,则getline将继续等待输入。如果信号发生在读取过程中,您仍然会得到-1,并且您必须在恢复之前清除()流。但是如果读取被阻塞等待数据并且信号发生,则使用SA_RESTART,您会在信号处理程序成功执行后立即返回读取。

我个人希望能够中断getline()所以我可以很好地终止一个等待管道的程序并且遇到麻烦,因为我使用旧的signal()方法来设置我的处理程序。所以我会得到信号,但getline永远不会被中断,因为读取被阻止等待数据,它只会在我的信号处理程序执行后自动重新启动读取。当我移动到sigaction结构并设置sa_flags = 0时,它中断了getline,导致它基本上返回EINTR,我可以向我的进程发送一个信号告诉它关闭。

我喜欢这个论坛。我无法计算它帮助解决棘手问题的次数。以为我会回馈。希望这有助于下一个程序员!