【问题标题】:How to handle EINTR (interrupted System Call)如何处理 EINTR(中断的系统调用)
【发布时间】:2009-11-04 14:40:08
【问题描述】:

不知何故,我的用户空间应用程序有时会在收到 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 后被完全阻止(请参阅 strace 转储:我发送了一个通常应该处理的 SIGUSR1)?为什么 futex() 会将 ERESTARTSYS 返回到用户空间?

谢谢

【问题讨论】:

  • EINTR 不是信号,而是系统调用被信号中断时返回的错误号。
  • 使用gstackgdb获取堆栈跟踪,找出程序当前卡在哪里。

标签: c++ c linux


【解决方案1】:

调用 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 宏,可能会引起人们的兴趣,尽管我在需要时找不到它的文档。包括现在。

【讨论】:

  • 谢谢,我在gnu.org/s/libc/manual/html_node/Interrupted-Primitives.html 找到了宏的文档你知道关于锁定的 futex() 函数吗?
  • 不了解 ERESTARTSYS。我认为这是一个内部实现细节 - 你在跟踪中看到它,但不应该看到它返回给用户代码,因为用户模式系统代码应该重试返回它的调用,或者将其转换为 EINTR .但我可能错了,我上一次刮胡子是在星期六,因此没有完整的 linux geek 凭证;-)
  • futex 是一个特定于 Linux 的“轻等待”锁定框架,用于构建信号量和互斥锁等更高级别的东西。参见 futex(7)。
  • 假设是 Linux,请查看题为“信号处理程序中断信号调用和库函数”的“man 7 signal”部分。这是一个很好的参考。
猜你喜欢
  • 1970-01-01
  • 2021-07-03
  • 2011-06-24
  • 2014-11-02
  • 2012-03-23
  • 2013-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多