2009-11-04 113 views
5

我的用户空间模块接收EINTR信号,后不知何故有时应用。如何处理EINTR(系统调用被中断)

我什么记录使用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信号,我怎么能重复来电关注诸如写入,读取或选择?即使我使用第三方库处理系统调用,如何确定发生了这个EINTR?

为什么我的应用程序接收到EINTR(:我发了SIGUSR1通常的处理方式,请参阅strace转储)之后被完全阻塞?为什么futex()将ERESTARTSYS返回给用户空间?

感谢

+3

讨论EINTR不是信号但在一个系统调用信号中断的错误数返回。 – 2009-11-04 15:06:22

+0

使用'gstack'或'gdb'获取堆栈跟踪,找出程序当前停滞的地方。 – mark4o 2009-11-04 16:08:01

回答

17

这就要求写(或其他阻塞操作)的代码必须知道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宏当我想要它们时,永远无法找到它的文档。包括现在。

+1

谢谢,我发现的Docu于宏在http://www.gnu.org/s/libc/manual/html_node/Interrupted-Primitives.html 你了解一下futex的锁定()函数? – Maus 2009-11-04 15:11:05

+1

不知道ERESTARTSYS。我认为这是一个内部实现细节 - 你可以在跟踪中看到它,但不应该看到它返回给用户代码,因为用户模式系统代码应该重试返回它的调用,否则将其转换为EINTR 。但我可能是错的,我最后剃上周六,因此没有像完整的Linux怪胎凭据;-) – 2009-11-04 15:16:17

+2

futex的事情是建立更高层次的东西就像一个信号灯Linux特有的“轻等待”锁定框架和互斥体。见futex(7)。 – 2009-11-04 15:21:29