How can you wait until all children and grand-children have exited, without blocking in a signal handler? This is my attempt so far.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int run = 1;
void handler(int sig, siginfo_t *info, void *uap)
{
int exit_code;
printf("sigchld pid %d\n", info->si_pid);
pid_t pid = waitpid(-1, &exit_code, 0);
if (pid == -1) {
perror("waitpid()\n");
} else {
printf("waitpid returned %d\n", pid);
}
// set run = 0 when all children exit
printf("end of sigchild handler\n");
}
void main() {
struct sigaction chld;
chld.sa_sigaction = handler;
chld.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
sigaction(SIGCHLD, &chld, NULL);
//procmask sigchld?
if (!fork ()) {
if (!fork ()) {
sleep(2);
printf ("grand-son exit: %d\n", getpid());
exit (0);
}
sleep(1);
printf ("son exit: %d\n", getpid());
exit (0);
}
while(run)
sleep(1);
printf("ciao\n");
}
While it is true that SIGCHLD and waitpid
, etc., only work for immediate children, on UNIX systems you can often "cheat" a little bit with inherited resources passed from parent to child to grandchild, and closed upon process termination.
For example, the original process might open a pipe
, and perhaps set the read end of it close-on-exec, so that children and grandchildren inherit the write end. When the original process is ready to wait for all descendants to terminate, it closes its write end of the pipe and blockingly read
s or select
s for readability on the remaining descriptor. When the last descendant has terminated, the read end of the pipe will deliver an EOF.
This tactic is not guaranteed — a child or grandchild might cautiously close inherited file descriptors — but it often works well enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With