I am trying to write a program in which I am forking a child from a parent, and handling SIGCHLD signals using a handler, in which I use waitpid(). When I execute it, however, I am sometimes getting a return value of 0 from waitpid, along with errno being set to EINTR. What does that mean?
Here is my SIGCHLD handler:
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;
Here is the parent function, in which I fork the child:
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;
When called with WNOHANG
, waitpid()
returns 0
when there are no more children left to reap. Your SIGCHLD
handler gets called when a child process exits, so you know there'll always be at least one to reap. But because multiple signals don't get queued, it's possible there might be more than one child process to reap.
So what this while
loop does:
while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)
is to basically say "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."
Returning 0
here is therefore not an error, it's a deliberate device to reap an unknown number of children. waitpid()
is not setting errno
, in this case, so that EINTR
must have been set when some previous system call got interrupted.
Generally speaking, you should not check errno
unless a function returns an error, although there are some unusual cases (strtol()
is one, where a return of 0
could mean the parsed number was 0
, or could mean that there was an error) where the return value does not unambiguously indicate an error. In these cases you can set errno
to 0
prior to calling the function, and in the event the return value suggests there might be an error, you can check errno
to see if it's been set.