Super Monkey has asked for the wisdom of the Perl Monks concerning the following question:

This might be an easy one.... After I fork, my parent process sleeps for a while and then kills the child process and continues parsing the results of the child. The child process spawns another process via backticks. The problem is, when I kill the child process it's spawned process continues running. Is there a solution short of greping the process table to get the childs subprocess PID to kill also? Here is a snippet of my code ...

my $child = fork(); if ($child) { sleep $sleep; kill 9, $child; # parse $fileName here } else { my $flag = `/usr/sbin/tcpdump -i eth0 -w $fileName`; }

Edit by myocom: Added code tags

Replies are listed 'Best First'.
•Re: Killing a Forked Subprocess
by merlyn (Sage) on Mar 21, 2002 at 18:10 UTC
Re: Killing a Forked Subprocess
by dws (Chancellor) on Mar 21, 2002 at 18:13 UTC
    If your child process is spawning other processes, you're going to need a signal less drastic than a kill -9. Use a signal that can be trapped. And your child process is going to need to cooperate by setting up a signal handler and voluntarily going to the grave.
Re: Killing a Forked Subprocess
by lestrrat (Deacon) on Mar 21, 2002 at 18:13 UTC

    Update: If signal selection is the real problem as merlyn and dws are pointing out, the below code might be overkill or just totally off the mark.


    On *nix, you might be able to use setpgrp() to send a kill signal to the process group, not just the forked process

    ## pseudocode, so won't do any good as it is if( $i_am_the_child ) { setpgrp(); `some_cmd`; } else { ## parent sleep $sleepamt; ## I think 15 is SIGTERM. please confirm on ## on your system kill -15, getpgrp( $child_pid ); }

    While I think the above idiom is correct, I suggest you read perldoc -f kill and setpgrp to make sure that that's what you want... ;)

      I think 15 is SIGTERM. please confirm on your system

      Just use symbolic names for signals and don't worry about numbers:

      kill 'SIGTERM', getpgrp( $child_pid );

      --
      Ilya Martynov (http://martynov.org/)

        Wouldn't the symbolic name be 'TERM', not 'SIGTERM' ? And also, since you're sending the signal to a process group, don't you need to give it a negative signal value?

        =item kill LIST Sends a signal to a list of processes. The first element of the list must be the signal to send. Returns the number of processes successfully signaled. $cnt = kill 1, $child1, $child2; kill 9, @goners; Unlike in the shell, in Perl if the I<SIGNAL> is negative, it kills process groups instead of processes. (On System V, a negative I<PROCE +SS> 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. See L<perlipc/"Signals"> for details.
      Thanks for you suggestion. I had tried something similar but was unsuccessful because I didn't use the <nobr>getpgrp($child_pid)</nobr> part. It seems to be the solution I was looking for.
Re: Killing a Forked Subprocess
by Zaxo (Archbishop) on Mar 21, 2002 at 19:17 UTC

    SIGTERM would be better. The child's handler should pass along the signal to its children. How about doing it this way, instead?

    my $pid = open TRAFFIC, "-|", "/usr/sbin/tcpdump", "-i", "eth0" or di +e $!;
    That gives you the child pid directly if you need it. You can handle the sampling interval with localtime or, on some systems:
    my ($rin,$rout); vec( $rin, fileno( TRAFFIC), 1) = 1; while( ($num,$sleep) = select($rout=$rin,undef,undef,$sleep)) { last if $sleep <= 0; # read TRAFFIC and process }
    Or use IO::Select.

    When you're done, just close TRAFFIC to kill off the real child. Doing it this way avoids the temporary file, removes an unnecessary process, gives you record-at-a-time memory usage, and lets you use cycles where both parent and child are sleeping in the present design.

    After Compline,
    Zaxo