On Jul 31, 2006, at 5:35 PM, Ted Zeng wrote:
I don't know how the OS generate the pid for a process. That is why I don't
feel comfortable with what I did.

The way I understand it, the OS assigns the next highest available pid when creating a process. However, pids wrap around when they reach the maximum
defined pid.  So, if your process' pid is near the max, your child could
get a lower pid.

What you want to do is find the pid of your child's child. There's probably a system call you can make to find these things, but I don't know it. What I do know is how to use "ps -j" or "ps -l". I've whipped up the following
script to demonstrate the technique.

Note: the script you're waiting on may have spawned off children of it's own, so it'd be a good idea to find them and kill them first. This, of course,
may let the script spawn off even more processes...

==== start demo script ====
#!/usr/bin/perl

use POSIX qw(:sys_wait_h);  # need this to get non-blocking waitchild

$|=1; # autoflush on

unless (defined($kid_pid = fork())) {
    die "Cannot fork: $!";
}

if ($kid_pid == 0) {
    # we're running as the child process
    execNightshade();
}
else {
    print "Watching child $kid_pid...\n";
    my $count=0;
    my $tConstant = 1; ## I'm impatient
    do {
        print "Sleeping ... ";
        sleep 10;
        $count++;
        $kid = waitpid($kid_pid, WNOHANG);
        print "kid: $kid_pid, waitpid: $kid\n";
    } until ($kid > 0 or $count > $tConstant);

    if ($count > $tConstant ) {
        recursive_kill($kid_pid);
    }
}

sub execNightshade {
    # since we don't know what execEggplant does beside exec-ing shell
    # scripts with ``, let's make something up...

my $count = join q{ }, 1 .. 10; # make a string '1 2 3 4 5 6 7 8 9 10'

    # this shell script prints numbers from 1 to 100, sleeping 10
    # seconds between each number...
    my $output = `for i in $count; do echo "\$i"; sleep 10; done`;

    # what good is output if we don't use it?
    print "$output\n";
}

sub recursive_kill {
    my($pid) = @_;

    while (my $child = child_pid($pid)) {
        # kill all its children, grandchildren, etc...
        recursive_kill($child);
    }

    # then kill the process itself
    print "Killing $pid\n";
    kill 9, $pid;
}

sub child_pid {
    my($parent) = @_;

    # we want to know the process id of the child that's been forked
    # by our own child.  since OS X is a unix, we can use ps to find
    # it.  the following highly non-portable code should work on OS X
    # and _maybe_ some other unices, but definately won't work on
    # WinAnything or other, stranger OSes...

    my $grandkid_pid;
    open my $ps, "ps -l |";
    while (<$ps>) {
        # unless the first field is numeric, we're looking at the
        # column headings.  let's discard it.
        next unless /^ \s* \d+ /msx;

        # split /PATTERN/,EXPR,LIMIT
        #
        # If EXPR is omitted, splits the $_ string.  If PATTERN is
        # also omitted, splits on whitespace (after skipping any
        # leading whitespace).
        #
        # As a special case, specifying a PATTERN of space (' ')
        # will split on white space just as "split" with no
        # arguments does.

        my($uid, $pid, $ppid, $other_fields) = split q{ }, $_, 4;

        # if the process' parent pid isn't our kid's pid, we're
        # not interested in it
        next unless ($ppid == $parent);

        # congratulations!  you're a parent!
        return $pid;
    }
    return; # if there's no child, just return
}
==== end demo script ====

Sample output:
$ pid_test.pl
Watching child 7718...
Sleeping ... kid: 7718, waitpid: 0
Sleeping ... kid: 7718, waitpid: 0
Killing 7724
Killing 7729
Killing 7733
Killing 7736
Killing 7739
Killing 7742
Killing 7745
Killing 7748
Killing 7751
1
2
3
4
5
6
7
8
9
10

Killing 7719
Killing 7718
$

What's happening is the script is killing the 'sleep', and then before
the subroutine can return and kill off the for loop, it's sleeping again.
Fortunately, it disposes of the sleeps fairly quickly, and the child
process actually returns its data before it gets killed.

--
Packy Anderson [EMAIL PROTECTED]

Catapultam habeo. Nisi pecuniam omnem mihi dabis, ad caput tuum saxum
immane mittam.


Reply via email to