An often overlooked concept are process group IDs.
Just create a new process group before you fork. Then, independently of
how many children are being forked, and how deep their fork/exec level
gets, you can address all of them in one go. A short demo:
#!/usr/bin/perl
my $sid = getppid; # for the 'ps' only
if (my $pid = fork()) {
sleep 1; # wait somewhat until tree of children is set up
# show related processes
system "ps f -s $sid -o pid,ppid,pgrp,sid,cmd";
# kill process group after timeout
sleep 5;
kill -9, $pid;
wait;
print "killed children\n";
# show remaining processes
system "ps f -s $sid -o pid,ppid,pgrp,sid,cmd";
# do something else...
sleep 5;
} elsif (defined $pid) {
# create new process group
setpgrp;
# run something (consisting of several processes) that hangs
system 'bash -c "cat; echo"';
exit;
} else {
die "couldn't fork";
}
__END__
Sample output:
$ ./726031.pl
PID PPID PGRP SID CMD
29171 29169 29171 29171 bash -rcfile .bashrc
508 29171 508 29171 \_ /usr/bin/perl ./726031.pl
509 508 509 29171 \_ /usr/bin/perl ./726031.pl
510 509 509 29171 | \_ bash -c cat; echo
511 510 509 29171 | \_ cat
512 508 508 29171 \_ ps f -s 29171 -o pid,ppid,pgrp,sid,cmd
killed children
PID PPID PGRP SID CMD
29171 29169 29171 29171 bash -rcfile .bashrc
508 29171 508 29171 \_ /usr/bin/perl ./726031.pl
513 508 508 29171 \_ ps f -s 29171 -o pid,ppid,pgrp,sid,cmd
As you can see in the PGRP column, the three child processes in
question all belong to the same process group (here 509). The single
kill addressed to this group gets rid of all three processes.
The only issue you might run into is when some process further
down the line itself creates another new process group. But as the
concept is largely unknown/unused, the chances you'll encounter that
problem in practice are rather low :) At least, it's worth a try.
|