waitpid()返回值0以及errno EINTR

时间:2015-03-27 23:45:41

标签: c system waitpid

我正在尝试编写一个程序,其中我从父母那里分配一个孩子,并使用处理程序处理SIGCHLD信号,我在其中使用waitpid()。但是,当我执行它时,我有时会从waitpid获得0的返回值,并且errno被设置为EINTR。这是什么意思?

这是我的SIGCHLD处理程序:

pid_t pid;
int status;

while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)
{
    printf("Handler reaped child %d\n", (int)pid);
    if(WIFEXITED(status))
    {
        deletejob(job_list, pid);
    }
    else if(WIFSIGNALED(status))
    {
        deletejob(job_list, pid);
    }
    else if(WIFSTOPPED(status))
    {
        struct job_t *job = getjobpid(job_list, pid);
        job->state = ST;
    }
}

printf("%d %d\n", pid, errno);
if(errno != ECHILD)
{
    unix_error("waitpid error");
}

return;

这是父函数,我在其中分叉子:

    pid_t pid;
    sigset_t block_set;
    int file_descriptor;
    if(tok.outfile == NULL)
    {
        file_descriptor = STDOUT_FILENO;
    }
    else
    {
        file_descriptor = open(tok.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    }

    sigemptyset(&block_set);
    sigaddset(&block_set, SIGCHLD);
    sigaddset(&block_set, SIGINT);
    sigaddset(&block_set, SIGTSTP);
    sigprocmask(SIG_BLOCK, &block_set, NULL);

    pid = fork();

    if(pid == 0)
    {
        sigprocmask(SIG_UNBLOCK, &block_set, NULL);
        setpgid(0, 0);
        dup2(file_descriptor, 1);

        while(execve(tok.argv[0], tok.argv, environ) < 0)
        {
            exit(0);
        }
    }
    else
    {
        if(bg == 1)
        {
            addjob(job_list, pid, BG, cmdline);
            sigprocmask(SIG_UNBLOCK, &block_set, NULL);
            int jid = pid2jid(pid);
            printf("[%d] (%d) %s\n", jid, pid, cmdline);
        }
        else if(bg == 0)
        {
            addjob(job_list, pid, FG, cmdline);
            sigprocmask(SIG_UNBLOCK, &block_set, NULL);
        }

        if(bg == 0)
        {
            struct job_t *job = getjobpid(job_list, pid);
            while(pid == fgpid(job_list))
            {
                sleep(1);
            }
        }
    }
}

return;

1 个答案:

答案 0 :(得分:3)

当使用WNOHANG跟注时,waitpid()会在没有更多孩子收获时返回0。当子进程退出时,会调用您的SIGCHLD处理程序,因此您知道总会有至少一个处理器收到。但是因为多个信号没有排队,所以可能有多个子进程可以收获。

那么while循环的作用是什么:

while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)

基本上是说“呼叫waitpid()收获我知道正在等待的孩子,然后一遍又一遍地呼叫它以收获可能碰巧可用的任何其他孩子,直到它返回{{1} },此时我知道我收集了所有可用的孩子。“

因此,返回0不是一个错误,它是一个有意识的设备来收获未知数量的孩子。在这种情况下,0未设置waitpid(),因此必须在某些先前的系统调用中断时设置errno

一般来说,除非函数返回错误,否则不应检查EINTR,尽管存在一些异常情况(errno为1,strtol()的返回可能意味着已解析number为0,或者可能表示存在错误)返回值未明确指示错误。在这些情况下,您可以在调用函数之前将0设置为errno,如果返回值表明可能是错误,则可以检查{{1查看是否已设置。