If I have a long-running system
command like apt-cache search <some query>
, is there a way to forward a SIGINT
sent via ^C
on the command line to the parent Perl process in such a way that all child processes are reaped.
This example does not have the desired behavior. The signal is sent to the child process.
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie;
# long running command on ubuntu, produces a ton of output.
# replace with your favorite long running command
system("apt-cache search hi");
print("Perl did not catch SIGINT even with autodie\n");
I tried searching around for ways of capturing the pid of the child that would be created by system("apt-cache search hi &")
, but couldn't find any, so I tried fork
ing and exec
ing the process and writing a signal handler. This doesn't work because apt-cache
itself launches a few processes via the clone
system call. Hand-rolling some logic to walk part of the process tree and clean up the
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie;
my $cpid;
$SIG{INT} = sub {
kill 'KILL', $cpid;
exit;
};
# long running command on ubuntu, produces a ton of output.
# replace with your favorite long running command
$cpid = fork;
if ($cpid == 0) {
exec 'apt-cache', 'search', 'hi';
}
print "Perl did not catch SIGINT even with autodie\n";
I guess essentially what I want is either a way of determining whether a child process launched by system
exited due to a signal like SIGINT
so I can have the Perl script clean up after itself or a way of walking the child processes and reaping them in such a way that strange edge cases of process management are handled cleanly and portably.
Make the child the head of a process group, then send the signal to the whole process group.
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use POSIX qw( setpgid );
my $child_pid;
$SIG{INT} = sub {
kill INT => -$child_pid if $child_pid;
exit(0x80 | 2); # 2 = SIGINT
};
my $child_pid = fork();
if (!$child_pid) {
setpgid($$);
exec 'apt-cache', 'search', 'hi';
}
WAIT: {
no autodie;
waitpid($child_pid, 0);
redo WAIT if $? == -1 and $!{EINTR};
die $! if $? == -1;
}
exit( ( $? >> 8 ) | ( 0x80 | ( $? & 0x7F ) ) );
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