系统调用和EINTR错误代码

时间:2014-09-08 17:33:53

标签: c posix interrupt system-calls eintr

那里有专家可以帮助我解决以下问题吗?

我在C中有以下系统调用:

access()
unlink()
setsockopt()
fcntl()
setsid()
socket()
bind()
listen()

我想知道他们是否会因错误代码-1和错误的EINTR / EAGAIN而失败。

我是否应该为这些处理EINTR / EAGAIN?

文档中没有提到与EINTR / EAGAIN相关的任何内容,但我看到很多人都在处理它。

哪个是正确的?

以下是我如何注册信号处理程序:https://gitorious.org/zepto-web-server/zepto-web-server/source/b1b03b9ecccfe9646e34caf3eb04689e2bbc54dd:src/signal-dispatcher-utility.c

使用此配置:https://gitorious.org/zepto-web-server/zepto-web-server/source/b1b03b9ecccfe9646e34caf3eb04689e2bbc54dd:src/server-signals-support-utility.c

此处还有一个提交,我在一些我知道返回EINTR或EAGAIN的系统调用中添加了一些EINTR / EAGAIN处理:https://gitorious.org/zepto-web-server/zepto-web-server/commit/b1b03b9ecccfe9646e34caf3eb04689e2bbc54dd

4 个答案:

答案 0 :(得分:4)

除非你安装了一个中断信号处理程序(一个安装有sigaction省略SA_RESTART标志的处理程序,或者在某些系统上安装了signal函数的处理程序),否则你不应该看到{ {1}} 根本

在您的特定功能列表中,除了EINTR之外,我看不到任何可能会遇到EINTR的情况,只有当它用于锁定时才会出现。但是John的回答中的链接应该有助于回答有关特定功能的问题。

答案 1 :(得分:3)

请参阅http://man7.org/linux/man-pages/man7/signal.7.html - 开始阅读它所在的底部附近"中断系统调用和库函数......"这是一个Linux手册页,但该信息通常适用于任何Unix / Posix / Linux风格的系统。

答案 2 :(得分:2)

在* NIX系统调用的每个手册页中都有一个名为ERRORS的部分。请参阅手册,例如:http://man7.org/linux/man-pages/man2/accept.2.html。您还可以使用命令行man accept进行查看。

通常,可能需要一些时间来计算的系统调用可以在信号传递和短系统调用上设置-1 + EINTR。例如,accept()可以阻止您的进程,因此它可以被信号中断,但是setsid()非常短,以至于它被写入不被信号中断。

答案 3 :(得分:0)

signal(7)用于Linux列表

accept
connect
fcntl
flock
futex
ioctl
open
read
readv
recv
recvfrom
recvmsg
send
sendmsg
sendto
wait
wait3
wait4
waitid
waitpid
write
writev

可能是no-SA_RESTART处理程序可中断(EINTR)和

setsockopt
accept
recv
recvfrom
recvmsg
connect
send
sendto
sendmsg
pause
sigsuspend
sigtimedwait
sigwaitinfo
epoll_wait
epoll_pwait
poll
ppoll
select
lect
msgrcv
msgsnd
semop
semtimedop
clock_nanosleep
nanosleep
read
io_getevents
sleep

作为EINTR可中断,即使是SA_RESTART处理程序。

此外,它列出:

setsockopt
accept
recv
recvfrom
recvmsg
connect
send
sendto
sendmsg
epoll_wait
epoll_pwait
semop
semtimedop
sigtimedwait
sigwaitinfo
read
futex
msgrcv
msgsnd
nanosleep

由于停止信号+ SIGCONT可以中断EINTR,并且表示此特定行为是特定于Linux的,而不是POSIX.1批准的。

除此之外,特别是如果函数的规范没有列出EINTR,你就不应该EINTR

如果您不信任系统来支持它,您可以尝试用SIGSTOP / SIGCONT + no-SA_RESTART信号轰炸您怀疑系统功能的循环no-op处理程序,看看你是否可以引出EINTR。

我尝试过:

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static void chld(int Sig)
{
    int status;
    if(0>wait(&status))
        _exit(1);
    if(!WIFEXITED(status)){ 
        //this can only interrupt an AS-safe block
        assert(WIFSIGNALED(status) && WTERMSIG(status) == SIGALRM);
        puts("OK");
        exit(0);
    } else {
        switch(WEXITSTATUS(status)){
        case 1: puts("FAIL"); break;
        case 2: puts("EINTR"); break;
        }
    }
    exit(0);
}
static void nop(int Sig)
{
}

int main()
{
    sigset_t full;
    sigfillset(&full);
    sigaction(SIGCHLD, &(struct sigaction){ .sa_handler=chld, .sa_mask=full, .sa_flags=0 } , 0); 
    sigaction(SIGUSR1, &(struct sigaction){ .sa_handler=nop, .sa_mask=full, .sa_flags=0 } , 0); 

    pid_t p;
    if(0>(p=fork())) { perror(0); return 1; }
    if(p!=0){
        //bombard it with SIGSTOP/SIGCONT/SIGUSR1
        for(;;){
            usleep(1); kill(p, SIGSTOP); kill(p, SIGCONT); kill(p, SIGUSR1);
        }
    }else{
        sigaction(SIGCHLD, &(struct sigaction){ .sa_handler=SIG_DFL }, 0);
        if(0>alarm(1))
            return 1;
        for(;;){

    #if 1
            /*not interruptible*/
            if(0>access("/dev/null", R_OK)){

                if(errno==EINTR)
                    return 2;
                perror(0);
                return 1;
            }

    #else
            int fd;
            unlink("fifo");
            if(0>mkfifo("fifo",0600))
                return 1;

            /*interruptible*/
            if(0>(fd=open("fifo", O_RDONLY|O_CREAT, 0600))){
                if(errno==EINTR)
                    return 2;
                perror(0);
                return 1;
            }
            close(fd);
    #endif

        }
    }
    return 0;
}

unlinkaccess肯定看起来是EINTR不可中断的(符合他们的规范),这意味着围绕它们的EINTR - 重试循环是不必要的。