Selling cookie info to third-parties is a classic example of you can make money without doing evil.
RSS

Kill those pesky forked children!

2009/08/06 filed under /perl

During some test writing, I had to spawn a shell command that would run while /bin/true was true. Unfortunately, my test script figured the run time should be limited, so I had to kill that little brat myself.

Let's have a look at a simplified setup first:

my $pid = fork();
if($pid == 0) {
    print "I'm the child: $$\n";
    system('while(/bin/true); do echo "Mwuahaha"; sleep 1; done');
} else {
    print "I'm the parent: $$\n";
}

sleep 3;
kill 1, $pid;

Although this might look valid perl, the "Mwhuahaha" will continue to fill up you terminal. The forked system command will not be killed when your program ends.

There had to be a way to kill the child (grandchild, if you want), and there is. Using setpgrp and getpgrp to the rescue!

Let's have a look at the documentation first (always a good thing):

   setpgrp PID,PGRP
       Sets the current process group for the specified PID, 0 for the
       current process. Will produce a fatal error if used on a
       machine that doesn't implement POSIX setpgid(2) or BSD
       setpgrp(2).  If the arguments are omitted, it defaults to
       "0,0".  Note that the BSD 4.2 version of "setpgrp" does not
       accept any arguments, so only "setpgrp(0,0)" is portable.  See
       also "POSIX::setsid()".

   getpgrp PID
       Returns the current process group for the specified PID.  Use a
       PID of 0 to get the current process group for the current
       process.  Will raise an exception if used on a machine that
       doesn' implement getpgrp(2).  If PID is omitted, returns
       process group of current process.  Note that the POSIX version
       of "getpgrp" does not accept a PID argument, so only "PID==0"
       is truly portable.

Almost there! Let's see the kill documentation as well, for it contains a fatal clue:

       Unlike in the shell, if SIGNAL is negative, it kills process
       groups instead of processes.  (On System V, a negative PROCESS
       number will also kill process groups, but that's not portable.)
       That means you usually want to use positive not negative
       signals.  You may also use a signal name in quotes.

Note that we need the negative signal!

So, if we change our test script to this, it'll all work, and those pesky (grand)children are killed when we want to:

my $pid = fork();
if($pid == 0) {
    setpgrp;
    print "I'm the child: $$\n";
    system('while(/bin/true); do echo "Mwuahaha"; sleep 1; done');
} else {
    print "I'm the parent: $$\n";
}

sleep 3;
kill -1, getpgrp($pid);

Posted by: B10m | permanent link | comments (0)
Comments are closed for this story.
Trackbacks are closed for this story.
return-member