简体   繁体   中英

System calls and EINTR error code

Is there any expert out there that can help me with the following?

I have the following system calls in C:

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

I want to know if they may fail with error code -1 and errno EINTR/EAGAIN.

Should I have to handle EINTR/EAGAIN for these?

The documentation do not refer anything related to EINTR/EAGAIN but many people I see handle it.

Which is the correct?

Here is how I register signal handlers : https://gitorious.org/zepto-web-server/zepto-web-server/source/b1b03b9ecccfe9646e34caf3eb04689e2bbc54dd:src/signal-dispatcher-utility.c

With this configuration: https://gitorious.org/zepto-web-server/zepto-web-server/source/b1b03b9ecccfe9646e34caf3eb04689e2bbc54dd:src/server-signals-support-utility.c

Also here is a commit that I added some EINTR/EAGAIN handling in some system calls that I know that return EINTR or EAGAIN : https://gitorious.org/zepto-web-server/zepto-web-server/commit/b1b03b9ecccfe9646e34caf3eb04689e2bbc54dd

Unless you install an interrupting signal handler (one installed with sigaction omitting the SA_RESTART flag, or one installed with the signal function on some systems) you should not expect to see EINTR at all .

Among your particular list of functions, I don't see any that could experience EINTR anyway except fcntl , and for it, only when it's used for locking. The link in John's answer should be helpful answering questions about specific functions, though.

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

There is a section entitled ERRORS in every man page of *NIX system call. Refer to the manual, for example : http://man7.org/linux/man-pages/man2/accept.2.html . You can also use the command line man accept to view it.

In general, system calls that can take some time to compute can set -1+EINTR on signal delivery and short system calls not. For example, accept() can block your process so it can be interrupted by a signal, but setsid() is so short that it has been written to not be interrupted by signals.

signal(7) for Linux lists

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

as possibly interruptible (EINTR) by no-SA_RESTART handlers and

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

as EINTR-interruptible, even by SA_RESTART handlers.

Furthermore, it lists:

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

as EINTR-interruptible by a stopping signal + SIGCONT , and says this particular behavior is Linux-specific and not sanctioned by POSIX.1 .

Apart from these, especially if the function's specification doesn't list EINTR , you shouldn't get EINTR .

If you don't trust the system to honor it, you can try bombarding a loop with your suspected system function by SIGSTOP / SIGCONT +a signal with a no-SA_RESTART no-op handler and see if you can elicit an EINTR.

I tried that with:

#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;
}

and unlink and access definitely appear to be EINTR-uninterruptible (in compliance with their spec), which means an EINTR -retry loop around them would be unnecessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM