收到报警信号时,read()系统调用不会失败

时间:2013-08-31 13:48:49

标签: c macos signals alarm system-calls

这是我的服务器端代码(部分)

void timeout_handler(int value) {
    printf("Handler\n");
    return;
}

int main (int argc, char **argv) {
    [...]
    signal(SIGALRM, timeout_handler);
    alarm(seconds);
    int result = read(input_socket, buffer, sizeof(buffer));
    if (result == -1 && errno == EINTR) {
        printf("read() failed\n");
    }
    [...]
}

其中input_socket是与客户端正确连接的TCP套接字(如果我从客户端发送数据,服务器会收到它们)。

作为对警报信号的测试,我试图打开并连接套接字客户端而不发送任何数据。 我希望输出像

Handler
read() failed

但结果只是Handler消息,然后该过程仍处于活动状态。

为什么read()不会因errno=EINTR而失败?

1 个答案:

答案 0 :(得分:1)

同样在OSX上,当信号中断时,某些系统调用默认重启

siginterrupt()可用于更改此行为。以下行(调用alarm()之前的某个地方)应该完成这项工作,让程序按照OP的预期运行:

siginterrupt(SIGALRM, 1);

从OSX文档(我强调):

  

对于某些系统调用,如果在执行调用时捕获到信号并且过早地进行调用        终止后,呼叫会自动重启。 使用signal(3)安装的任何处理程序都将具有        SA_RESTART标志设置,这意味着任何可重新启动的系统调用都不会在收到信号时返回。        受影响的系统调用包括 read(2),write(2),sendto(2),recvfrom(2),sendmsg(2)和recvmsg(2)        在通信信道或低速设备上以及在ioctl(2)或等待(2)期间。但是,电话        已经提交的内容未重新启动,而是返回部分成功(例如,a        短读数)。可以使用siginterrupt(3)更改这些语义。

这在Linux上是不同的,例如,发送信号需要明确地请求重新启动系统调用。