I don't think it was race condition in this case, because this code should work with and without SIG CHLD IGNORE statement.
Fair enough; your further testing speaks to that. I'd still recommend setting up the handler before the kill, as a matter of good practice if nothing else.
Well, for example I want to reap zombies while program run, but at the same time I want to wait all child processes at exit.
OK. Luckily, that's quite easy to do, with only one wait in your code. See perlipc for more info, but here's a handler inspired by that:
use POSIX ':sys_wait_h'; # WNOHANG
my %pids; # Parent's hash of child pids
$SIG{CHLD} = sub {
local ($?, $!); # Don't change $! or $? outside handler
until (-1 == (my $pid = waitpid(-1, WNOHANG))) {
return if $pid == 0; # Processes still running
next unless delete $pids{$pid};
say "$pid exited with status $?";
}
};
In your parent, just set $pids{$pid} = 1 every time you fork, and the SIGCHLD handler will clean them up. In your parent's main loop, you then know not to exit until %pids is empty. You need to track your pids somehow, if you intend to send signals to them, so you may as well take advantage of that.