如何处理EINTR(中断的系统调用)

我的用户空间应用程序在收到EINTR-Signal后,有时会被阻塞。

我用strace录的:

time(NULL) = 1257343042 time(NULL) = 1257343042 rt_sigreturn(0xbff07be4) = -1 EINTR (Interrupted system call) --- SIGALRM (Alarm clock) @ 0 (0) --- time(NULL) = 1257343042 futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) --- SIGUSR1 (User defined signal 1) @ 0 (0) --- sigreturn() = ? (mask now [ALRM]) futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) --- SIGWINCH (Window changed) @ 0 (0) --- futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) --- SIGTERM (Terminated) @ 0 (0) --- time(NULL) = 1257343443 time(NULL) = 1257343443 futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2) = ? ERESTARTSYS (To be restarted) --- SIGWINCH (Window changed) @ 0 (0) --- futex(0xb7cea80c, 0x80 /* FUTEX_??? */, 2 

我可以捕捉到EINTR信号吗?我如何重复相关的呼叫,例如写入,读取或select? 即使我使用了系统调用的第三方库,我怎样才能确定发生了这个EINTR?

为什么我的应用程序在收到EINTR后完全被阻塞(请参阅strace dump:我发送了一个通常应该被处理的SIGUSR1)? 为什么futex()将ERESTARTSYS返回给用户空间?

谢谢

调用write(或其他阻塞操作)的代码必须知道EINTR。 如果在阻塞操作期间发生信号,则操作将(a)返回部分完成,或(b)返回失败,不执行任何操作,并将errno设置为EINTR。

因此,对于在中断后重试的全失败写操作,您可以这样做:

 while(size > 0) { int written = write(filedes, buf, size); if (written == -1) { if (errno == EINTR) continue; return -1; } buf += written; size -= written; } return 0; // success 

或者为了更好的表现,重试EINTR,写入尽可能多的内容,并报告写入失败的次数(因此,调用者可以决定是否以及如何继续部分写入,而不是由于信号中断而失败):

 int total = 0; while(size > 0) { int written = write(filedes, buf, size); if (written == -1) { if (errno == EINTR) continue; return (total == 0) ? -1 : total; } buf += written; total += written; size -= written; } return total; // bytes written 

GNU有一个非标准的TEMP_FAILURE_RETRY宏,可能会引起人们的兴趣,但是当我想要的时候,我永远无法找到它的文档。 包括现在。

另见“ 更糟糕的模式”的讨论更好