Crash Override Crash Override - 1 year ago 118
Perl Question

Kill children when the parent is killed

Is there an easy way for Perl to kill child processes when the parent is killed? When I run

on a parent PID the children stay alive.

Test script:


@sleeps = qw( 60 70 80 );
@pids = ();

foreach $sleeptime (@sleeps) {

my $pid = fork();

if ( not defined $pid ) {
elsif ( $pid == 0 ) {

system("sleep $sleeptime");
else {

push @pids, $pid;

foreach $pid (@pids) {
waitpid( $pid, 0 );

Answer Source

Update   Added example using END block, which is also more complete.
Note   An example on how to use the process group for this is at the end.

Most of the time chances are that you are dealing with SIGTERM signal. For this you can arrange to clean up child processes, via a handler. There are signals that cannot be trapped, notably SIGKILL and SIGSTOP. For those you'd have to go to the OS, per answer by Kaz. Here is a sketch for others. Also see other code below it, and comments below that.

use warnings;
use strict;
use feature qw(say);
say "Parent pid: $$";

$SIG{TERM} = \&handle_signal;  # Same for others that can (and should) be handled

END { say "In END block ..." }

my @kids;
for (1..4) {
    push @kids, fork;
    if ($kids[-1] == 0) { exec 'sleep 20' }
say "Started processes: @kids";
sleep 30;   

sub handle_signal { 
    my $signame = shift;
    say "Got $signame. Clean up child processes.";
    die "Die-ing for $signame signal";

sub clean_up_kids { 
    say "\tSending TERM to processes @_";
    my $cnt = kill 'TERM', @_;  
    say "\tNumber of processes signaled: $cnt";
    waitpid $_, 0 for @_;  # blocking

When I run this as & and then kill it, it prints

[13] 4974
Parent pid: 4974
Started processes: 4978 4979 4980 4982
prompt> kill 4974
Got TERM. Clean up child processes.
        Sending TERM to processes 4978 4979 4980 4982
        Number of processes signaled: 4
Die-ing for TERM signal at line 25.
In END block ...

[13]   Exit 4              

The processes do get killed, checked by ps aux | egrep '[s]leep' before and after kill.

By courtesy of die the END block gets executed orderly so you can clean up child processes there. That way you are also protected against uncaught die. So you'd use the handler merely to ensure that the END block cleanup happens.

use POSIX "sys_wait_h";
$SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) { } };  # non-blocking
$SIG{TERM} = \&handle_signal;

END { 
    my @live = grep { kill 0, $_ } for @kids;
    warn "Processes @live still running" if @live;

sub clean_up_kids { 
    my $cnt = kill 'TERM', @_;
    say "Signaled $cnt processes.";
sub handle_signal { die "Die-ing for " . shift }

Here we reap (all) terminated child processes in a SIGCHLD handler, see Signals in perlipc and waitpid. We also check in the end whether they are all gone.

Some notes. This is nowhere near to a full list of things to consider. Along with mentioned (and other) Perl docs also see UNIX and C documentation as Perl's ipc is built directly over UNIX system tools.

  • Practically all error checking is omitted here. Please add.

  • Waiting for particular processes is blocking so if some weren't terminated the program will hang. The non-blocking waitpid has another caveat, see linked perlipc docs.

  • Child processes may have exited before the parent was killed. The kill 'TERM' sends SIGTERM but this doesn't ensure that the child terminates. Processes may or may not be there.

  • There are modules for various aspects of this. See sigtrap pragma for example.

  • One is well advised to not do much in signal handlers.

  • There is a lot going on with this and errors can have far-ranging consequences.

If you kill the process group you won't have any of these issues, since all children are then terminated as well. On my system this can be done at the terminal by

prompt> kill -s TERM -pid

You may have to use a numeric signal, generally 15 for TERM, see man kill on your system. The -pid stands for the process group, signified by the minus sign. The number is the same as the process ID, but add say getpgrp; to the code to see. If this process has not been simply launched by the shell, but say from another script, it will belong to its parent's process group, and so will its children. Then you need to set its own process group first, which its children will inherit, and then you can kill that process group. See setpgrp and getpgrp, and search SO posts.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download