C 系统调用和EINTR错误代码

C 系统调用和EINTR错误代码,c,posix,interrupt,system-calls,eintr,C,Posix,Interrupt,System Calls,Eintr,有没有专家可以在以下方面帮助我 我在C中有以下系统调用: access() unlink() setsockopt() fcntl() setsid() socket() bind() listen() 我想知道它们是否会失败,错误代码为-1和errno EINTR/EAGAIN 我应该为这些处理EINTR/EAGAIN吗 文档中没有提到任何与EINTR/EAGAIN相关的内容,但我看到很多人都在处理它 哪个是正确的 以下是我如何注册信号处理程序: 使用此配置: 还有一个提交,我在一些系统调用

有没有专家可以在以下方面帮助我

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

access()
unlink()
setsockopt()
fcntl()
setsid()
socket()
bind()
listen()
我想知道它们是否会失败,错误代码为-1和errno EINTR/EAGAIN

我应该为这些处理EINTR/EAGAIN吗

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

哪个是正确的

以下是我如何注册信号处理程序:

使用此配置:


还有一个提交,我在一些系统调用中添加了一些EINTR/EAGAIN处理,我知道返回EINTR或EAGAIN:

请参见--开始阅读底部附近的内容,其中谈到“系统调用和库函数的中断…”这是一个Linux手册页,但是,这些信息通常适用于任何Unix/Posix/Linux风格的系统。

除非您安装了中断信号处理程序(一个安装了
sigaction
省略
sau RESTART
标志,或者在某些系统上安装了
signal
功能)您不应该期望看到
EINTR


在您的特定函数列表中,我没有看到任何函数可以体验到
EINTR
,除了
fcntl
,而且对于它,只有当它用于锁定时。John答案中的链接应该有助于回答有关特定功能的问题。

在*NIX系统调用的每个手册页中都有一个标题为“错误”的部分。请参阅手册,例如:。您还可以使用命令行
manaccept
查看它

通常,可能需要一些时间来计算的系统调用可以在信号传递时设置-1+EINTR,而短系统调用则不能。例如,
accept()
可以阻止进程被信号中断,但是
setsid()
太短了,所以它被写为不被信号中断。

用于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_重启处理程序中断(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_重启处理程序

此外,它还列出:

setsockopt
accept
recv
recvfrom
recvmsg
connect
send
sendto
sendmsg
epoll_wait
epoll_pwait
semop
semtimedop
sigtimedwait
sigwaitinfo
read
futex
msgrcv
msgsnd
nanosleep
由于EINTR可通过停止信号中断+
SIGCONT
,并表示此特定行为是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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
静态无效chld(内部信号)
{
智力状态;
如果(0>等待(&状态))
_出口(1);
如果(!WIFEXITED(status)){
//这只能中断AS安全块
断言(WIFSIGNALED(status)和&WTERMSIG(status)=SIGALRM);
卖出(“OK”);
出口(0);
}否则{
开关(状态(状态)){
案例1:看跌期权(“失败”);违约;
案例2:看跌期权(“EINTR”);违约;
}
}
出口(0);
}
静态无效nop(内部信号)
{
}
int main()
{
信号集未满;
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;
如果(0>(p=fork()){perror(0);返回1;}
如果(p!=0){
//用SIGSTOP/SIGCONT/SIGUSR1轰击它
对于(;;){
usleep(1);kill(p,SIGSTOP);kill(p,SIGCONT);kill(p,SIGUSR1);
}
}否则{
sigaction(SIGCHLD,&(struct-sigaction){.sa_handler=SIG_-DFL},0);
如果(0>报警(1))
返回1;
对于(;;){
#如果1
/*不可打断*/
如果(0>访问(“/dev/null”,R_确定)){
如果(errno==EINTR)
返回2;
perror(0);
返回1;
}
#否则
int-fd;
取消链接(“fifo”);
如果(0>mkfifo(“fifo”,0600))
返回1;
/*打断*/
如果(0>(fd=open(“fifo”,O|RDONLY | O|u CREAT,0600))){
如果(errno==EINTR)
返回2;
perror(0);
返回1;
}
关闭(fd);
#恩迪夫
}
}
返回0;
}

取消链接
访问
显然是EINTR不可中断的(符合其规范),这意味着围绕它们的
EINTR
重试循环将是不必要的

根据平台、系统调用和SA_重新启动标志,系统调用可能会失败,也可能不会失败,具体取决于EINTR。(在pep-0475中读取)可能重复的I已启用SA_重启。然而,我已经读到,显式地处理EINTR应该很好。还有其他想法吗?我应该处理呼叫的EINTR还是SA_重启就足够了?
EINTR
EAGAIN
意味着不同的事情。我建议总是编写代码来处理
EINTR
。如果您在没有请求的情况下得到了
EAGAIN
,那么您的程序或内核中都存在严重的逻辑错误。我已经安装了许多带有sigaction的信号处理程序,其中大多数都使用SA_RESTART。信号处理器也不能被中断。在一些文章和线程中,我已经读到,无论SA_重启如何,我们都应该检查EINTR。我正在使用HANDLE\u EINTR和HANDLE\u EAGAIN宏(摘自Chrome源代码)。还有其他想法吗?我应该为调用处理EINTR还是重新启动SA_就足够了?我已经阅读了它,对于引用的系统调用,我已经处理了EINTR。但是,只有这些是返回EINTR的系统调用?我不这么认为。许多人在其手册页未引用的其他系统调用中处理EINTR