Pervious answers to this questions have focused on forks:
For this question, I'm just asking about calls to the 'system' function.
Say I have a script called sleep.pl:
use strict;
use warnings;
sleep(300);
I then have a script called kill.pl
use strict;
use warnings;
system("sleep.pl");
I run kill.pl and using ps I find the process id of kill.pl and kill it (not using kill -9, just normal kill)
sleep.pl is still sleeping.
I imagine the solution to my question involves a SIG handler, but what do I need to put into the handler to kill the child process?
In the ssh window where it is running you can often just hit ctrl+c to kill it however there are some instances where that will not work. The kill command would be the next step.
Use setsid to make your process the new group leader. Then you can send a kill to the group ID and kill all processes that belong to the group. All processes that you spawn from the leader process inherit the group ID and belong to your newly created group. So sending a kill to the group will kill them all. The only tricky thing is in order to be able to use setsid you must close your standard in and output, as that is a requirement for setsid.
use strict;
use warnings;
setpgrp $$, 0;
system("sleep.pl");
END {kill 15, -$$}
But if you need this approach you do something wrong. You should not do this. Run and kill your kill process in right way instead.
$ perl -e 'system("sleep 100")' &
[1] 11928
$ ps f
PID TTY STAT TIME COMMAND
4564 pts/1 Ss 0:01 /bin/bash
11928 pts/1 S 0:00 \_ perl -e system("sleep 100")
11929 pts/1 S 0:00 | \_ sleep 100
11936 pts/1 R+ 0:00 \_ ps f
$ kill %1
[1]+ Terminated perl -e 'system("sleep 100")'
$ ps f
PID TTY STAT TIME COMMAND
4564 pts/1 Rs 0:01 /bin/bash
11949 pts/1 R+ 0:00 \_ ps f
How it works? Shell (bash in mine case) should set your process as group leader if you run on background. Then if you use kill %?
syntax shell kills group in right way. Compare this:
$ perl -e 'system("sleep 100")' &
[1] 12109
$ ps f
PID TTY STAT TIME COMMAND
4564 pts/1 Rs 0:01 /bin/bash
12109 pts/1 S 0:00 \_ perl -e system("sleep 100")
12113 pts/1 S 0:00 | \_ sleep 100
12114 pts/1 R+ 0:00 \_ ps f
$ kill 12109
[1]+ Terminated perl -e 'system("sleep 100")'
$ ps f
PID TTY STAT TIME COMMAND
4564 pts/1 Ss 0:01 /bin/bash
12124 pts/1 R+ 0:00 \_ ps f
12113 pts/1 S 0:00 sleep 100
But kill %?
works in this way:
$ perl -e 'system("sleep 100")' &
[1] 12126
$ ps f
PID TTY STAT TIME COMMAND
4564 pts/1 Rs 0:01 /bin/bash
12126 pts/1 S 0:00 \_ perl -e system("sleep 100")
12127 pts/1 S 0:00 | \_ sleep 100
12128 pts/1 R+ 0:00 \_ ps f
$ kill -12126
[1]+ Terminated perl -e 'system("sleep 100")'
$ ps f
PID TTY STAT TIME COMMAND
4564 pts/1 Ss 0:01 /bin/bash
12130 pts/1 R+ 0:00 \_ ps f
Your question really is a specific instance of the more general "how to ensure a child dies when the parent dies" question. There's just no getting around that. There's nothing really special about system(); it just forks a child process and waits for it to exit.
system() is roughly this:
sub system
{
my $kidpid = fork;
if ( $kidpid )
{
waitpid $kidpid;
# parent process blocks here waiting for the child process to return
}
else
{
exec( @_ );
}
}
Killing the process group is about your only option.
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