The problem
An error occurred in a function today with a probabilistic waitpid call. The error is No child processes. The prompt does not have this child process, the PID number can also be wrong, so add the print, when the duplicate found that the PID number can correspond to, no problem.
online, found “No child” the processes of error code corresponding ECHILD, waitpid there is in man’s document, if the process set the SIGCHLD signal processing to SIG_IGN, then the call will return ECHILD waitpid.
to see the code, the parent process does have to capture the SIGCHLD signal inside, for processing way
rc = waitpid(-1, &status, WNOHANG);
Wait for any child process to exit so that it can be recovered. I suspect that calling WaitPid again when the parent process has already collected its body will be an error. And that explains the probabilistic problem. So write the following code to verify it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
void sig_handle(int sig)
{
waitpid(-1, NULL, 0);
printf("llm->%s(%d)\n", __FUNCTION__, __LINE__);
}
int main(int argc, char *argv[])
{
int rtn = 0;
int pid = 0;
char *arg[] = {"date", NULL};
signal(SIGCHLD, sig_handle);
//signal(SIGCHLD, SIG_IGN);
while(1)
{
pid = fork();
if(!pid)
{
execvp("date", arg);
exit(1);
}
usleep(10*1000);
rtn = waitpid(pid, NULL, 0);
if(rtn < 0)
perror("waitpid");
//usleep(10*1000);
}
return 0;
}
If you add sleep before waitpid, the problem will be 100% duplicated. If you remove sleep, there will be no problem.
The solution
Given the current code logic, there is a problem with either Waitpid being removed, so the best course of action is to determine whether it is true or false. If Waitpid returns ECHILD, then ignore the error.
The system calls
This is not a problem with the system call. This is not a problem with the implementation of waitpid after fork. The implementation handles the signal accordingly. The SIGCHLD signal processing action is restored before fork, as follows:
int __libc_system(char *command)
{
int wait_val, pid;
__sighandler_t save_quit, save_int, save_chld;
if (command == 0)
return 1;
save_quit = signal(SIGQUIT, SIG_IGN);
save_int = signal(SIGINT, SIG_IGN);
save_chld = signal(SIGCHLD, SIG_DFL);
if ((pid = vfork()) < 0) {
signal(SIGQUIT, save_quit);
signal(SIGINT, save_int);
signal(SIGCHLD, save_chld);
return -1;
}
if (pid == 0) {
signal(SIGQUIT, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
execl("/bin/sh", "sh", "-c", command, (char *) 0);
_exit(127);
}
/* Signals are not absolutly guarenteed with vfork */
signal(SIGQUIT, SIG_IGN);
signal(SIGINT, SIG_IGN);
#if 0
printf("Waiting for child %d\n", pid);
#endif
if (wait4(pid, &wait_val, 0, 0) == -1)
wait_val = -1;
signal(SIGQUIT, save_quit);
signal(SIGINT, save_int);
signal(SIGCHLD, save_chld);
return wait_val;
}
weak_alias(__libc_system, system)