【问题标题】:waitpid() return value 0 along with errno EINTRwaitpid() 返回值 0 以及 errno EINTR
【发布时间】:2015-03-27 23:45:40
【问题描述】:

我正在尝试编写一个程序,在该程序中,我从父母那里分叉出一个孩子,并使用处理程序处理 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;

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

    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;

【问题讨论】:

  • waitpid() 如果指定WNOHANG,则在没有准备好收割的子进程时返回 0。由于它没有返回错误,因此您不应该检查errno。其他一些系统调用必须在之前被中断,然后设置它。
  • 好的。知道了。那么有什么方法可以检查哪个系统调用的中断设置了errno呢?
  • 是的,通过检查每个系统调用的返回值,并检查 errno 是否有任何返回错误。
  • 好的。我会去做的。谢谢您的帮助!!顺便说一句,删除检查 errno 解决了所述问题。
  • EINTR 可能发生在某个库函数中,不一定发生在您的直接系统调用之一中。一般来说,您应该忽略errno,除非您刚刚进行了报告错误的系统调用。

标签: c system waitpid


【解决方案1】:

当用WNOHANG 调用时,waitpid() 在没有更多的孩子可以收割时返回0。当子进程退出时,您的 SIGCHLD 处理程序会被调用,因此您知道总会有至少一个可以收获。但由于多个信号不会排队,因此可能有多个子进程需要获取。

那么这个while 循环做了什么:

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

基本上是说“调用waitpid() 来获取我知道正在等待的孩子,然后继续一遍又一遍地调用它来获取任何可能碰巧可用的其他孩子,直到它返回0,此时点我知道我已经收获了所有可用的孩子。”

因此,在此处返回 0 不是错误,它是一种蓄意获取未知数量孩子的手段。 waitpid() 没有设置errno,在这种情况下,EINTR 必须在之前的某个系统调用被中断时设置。

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

【讨论】:

  • 那么返回值为-1的唯一情况是调用过程中实际上没有孩子吗?我想只有在这种情况下,errno 才设置为 ECHILD。
  • waitpid() 可以出于多种原因返回 -1,例如传递一个不存在的特定 pid,或者传递无效选项,或者当你不这样做时它被信号中断'不指定WNOHANG。如果您以您的方式调用它,如果不存在指定类型的子进程,它将返回 -1(在这种情况下,这意味着任何子进程,因为您将 -1 指定为第一个参数)。
猜你喜欢
  • 2014-05-16
  • 2018-09-20
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
  • 2013-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多