6

有没有专家可以帮助我解决以下问题?

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

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

我想知道它们是否会因错误代码 -1 和 errno 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

4 回答 4

5

除非您安装一个中断信号处理程序(一个安装时sigaction忽略SA_RESTART标志,或者安装一个在某些系统上带有该功能),否则您根本signal不应该期望看到.EINTR

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

于 2014-09-08T17:41:22.673 回答
4

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

于 2014-09-08T17:38:51.497 回答
2

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

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

于 2014-09-08T18:13:55.263 回答
0

用于 Linux 列表的signal(7)

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

作为 EINTR 可被停止信号 + 中断SIGCONT,并表示此特定行为是 Linux 特定的,不受POSIX.1.

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

如果您不相信系统会尊重它,您可以尝试使用带有无操作处理程序的SIGSTOP/ SIGCONT+ 信号用您怀疑的系统功能轰炸循环,no-SA_RESTART看看您是否可以引出 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;
}

并且绝对看起来是 EINTR 不间断unlinkaccess(符合他们的规范),这意味着EINTR围绕它们的 -retry 循环将是不必要的。

于 2017-11-08T13:10:17.780 回答