waitpid() return 值 0 和 errno EINTR
waitpid() return value 0 along with errno EINTR
我正在尝试编写一个程序,在该程序中,我从父级派生出一个子级,并使用处理程序处理 SIGCHLD 信号,我在其中使用了 waitpid()。然而,当我执行它时,我有时会从 waitpid 获得一个 return 值 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;
当用 WNOHANG
、waitpid()
returns 0
调用时,没有更多的 children 可以收割。当 child 进程退出时,您的 SIGCHLD
处理程序会被调用,因此您知道总会有至少一个要收割。但是因为多个信号没有排队,所以可能有不止一个 child 进程要收割。
那么这个 while
循环做了什么:
while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)
基本上就是说"call waitpid()
to reap the child I know is waiting, and then keep calling it over and over to reap any additional children which may happen to be available, until it returns 0
, at which point I know I've reaped all the children that are available."
因此这里返回0
并不是一个错误,它是一个蓄意获取未知数量的children的装置。 waitpid()
没有设置 errno
,在这种情况下,所以 EINTR
一定是在之前的系统调用被中断时设置的。
一般来说,你不应该检查 errno
除非一个函数 return 是一个错误,虽然有一些不寻常的情况(strtol()
是一个,其中一个 [=44= 0
的 ] 可能意味着解析的数字是 0
,或者可能意味着有错误),其中 return 值没有明确指示错误。在这些情况下,您可以在调用函数之前将 errno
设置为 0
,如果 return 值表明 可能 是一个错误,您可以检查 errno
以查看是否已设置。
我正在尝试编写一个程序,在该程序中,我从父级派生出一个子级,并使用处理程序处理 SIGCHLD 信号,我在其中使用了 waitpid()。然而,当我执行它时,我有时会从 waitpid 获得一个 return 值 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;
当用 WNOHANG
、waitpid()
returns 0
调用时,没有更多的 children 可以收割。当 child 进程退出时,您的 SIGCHLD
处理程序会被调用,因此您知道总会有至少一个要收割。但是因为多个信号没有排队,所以可能有不止一个 child 进程要收割。
那么这个 while
循环做了什么:
while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)
基本上就是说"call waitpid()
to reap the child I know is waiting, and then keep calling it over and over to reap any additional children which may happen to be available, until it returns 0
, at which point I know I've reaped all the children that are available."
因此这里返回0
并不是一个错误,它是一个蓄意获取未知数量的children的装置。 waitpid()
没有设置 errno
,在这种情况下,所以 EINTR
一定是在之前的系统调用被中断时设置的。
一般来说,你不应该检查 errno
除非一个函数 return 是一个错误,虽然有一些不寻常的情况(strtol()
是一个,其中一个 [=44= 0
的 ] 可能意味着解析的数字是 0
,或者可能意味着有错误),其中 return 值没有明确指示错误。在这些情况下,您可以在调用函数之前将 errno
设置为 0
,如果 return 值表明 可能 是一个错误,您可以检查 errno
以查看是否已设置。