I have a parent process that spawns ten child processes and uses a SIGCHILD handler to notify when a child process has died. The child processes will notify when they have started and will then exit immediately.
I use the SA_NODEFER flag to prevent SIGCHLD signals to get discarded when too many are coming in. The children are all being correctly terminated and reaped, but in this script and also when terminating two at the same time via the console signals send at the same time always appear as one.
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
void CHLDHandler(int sig)
{
char child[] = "Child finished!\n";
write(1, &child, sizeof(child));
}
int main(int argc, char const *argv[]) {
struct sigaction sa;
sa.sa_handler = CHLDHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NODEFER;
sigaction(SIGCHLD,&sa,NULL);
for (size_t i = 0; i < 10; i++) {
int pid = fork();
if (pid == 0)
{
int pid = getpid();
printf("I'm a child with pid %d!\n", pid);
return 0;
}
}
while(1)
{
wait(NULL);
}
return 0;
}
Basic UNIX signals do not queue — only one can be pending (for a given thread) at a time.
If two child processes terminate at effectively the same time and thus deliver their SIGCHLD at the "same" time, your process will have only one signal pending.
wait
ing in a loop after receipt of a SIGCHLD is a long-established technique to compensate for the fact that a SIGCHLD may be "lost". Move the "Child finished!\n" announcement to the loop that callswait
, and you'll have an accurate count.UPDATE
If you must reap within your handler, you may call
wait
within the handler, since it is async-signal-safe:In this case I would not set SA_NODEFER, since another SIGCHLD might interrupt (EINTR) the
waitpid
or thewrite
calls.