tags:

views:

1692

answers:

3

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?

+3  A: 

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.

lothar
+2  A: 
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
Hynek -Pichi- Vychodil
In summary, use a negative PID.
Dennis Williamson
A: 

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.

Rob K