如何处理EINTR(系统调用被中断) [英] How to handle EINTR (interrupted System Call)

查看:223
本文介绍了如何处理EINTR(系统调用被中断)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的用户空间应用程序有时会收到EINTR信号,后不知何故块。

My user-space application sometimes blocks after receiving an EINTR-Signal, somehow.

我录什么跟strace的:

What I recorded with 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发生,即使我使用的第三方库与系统调用的工作?

Can I catch the EINTR signal and how can I repeat concerned calls such as write, read or select? How can I determine WHERE this EINTR occurred, even if I used third-party libraries working with system calls?

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

Why my app is completely blocked after receiving an EINTR (see strace dump: I sent a SIGUSR1 which normally should be handled)? And why is futex() returning ERESTARTSYS to user space?

感谢

推荐答案

在code这就要求写(或其他阻塞操作)必须知道EINTR的。如果阻塞操作过程中发生的信号,那么操作将是(a)返回部分完成,或(b)则返回失败,什么都不做,并设置errno为EINTR。

The code which calls write (or other blocking operations) has to be aware of EINTR. If a signal occurs during a blocking operation, then the operation will either (a) return partial completion, or (b) return failure, do nothing, and set errno to EINTR.

因此​​,对于一个全或失效而中断后重试写操作时,你会做这样的事情:

So, for an all-or-fail write operation which retries after interruptions, you'd do something like this:

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,写尽可能是可以的,有多少是失败的书面报告(所以调用者可以决定是否以及如何继续其失败以外的原因部分写入通过信号中断):

Or for something a bit better behaved, which retries EINTR, writes as much as it can, and reports how much is written on failure (so the caller can decide whether and how to continue partial writes which fail for a reason other than interruption by signal):

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 has a non-standard TEMP_FAILURE_RETRY macro that might be of interest, although I can never find the docs for it when I want them. Including now.

这篇关于如何处理EINTR(系统调用被中断)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆