Why doesn't waitpid wait for the process to exit?
Asked Answered
K

1

9

In the below script I am trying to figure out how waitpid works, but it doesn't wait for ssh process to exit. done is printed right away and not after the ssh process exists.

Question

How to I make waitpid only continue when the pid I give it have exited?

#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;
use POSIX ":sys_wait_h";

my $pm = Parallel::ForkManager->new(5);
my $pid = $pm->start;
my $p = $pid;
if (!$pid) {
    system("ssh 10.10.47.47 sleep 10");
    $pm->finish;
}

$p = qx(/usr/bin/pgrep -P $p);
print "ssh pid is $p\n";

my $kid;
do {
    $kid = waitpid($p, 0);
} while $kid > 0;

print "done\n";

I have also tried

while (1) {
    $p = kill 0, $p;
    print "x";
    sleep 1 if $p;
    print "*";
    last unless $p;
}

but it doesn't even reach the first print for some reason and never exits.

Karen answered 28/12, 2014 at 13:57 Comment(0)
C
9

The wait family of functions only work on child processes, even waitpid. The sleep process is not your child, it's your child's child. This is because system is essentially fork + exec. By using Parallel::ForkManager + system you're forking, then forking again, then executing sleep.

Since you've already forked, you should use exec. This has the extra advantage of not needing the call to pgrep and it's timing problem (ie. it's possible the parent will call pgrep before the child has executed system).

my $pm = Parallel::ForkManager->new(5);
my $pid = $pm->start;
my $p = $pid;
if (!$pid) {
    no warnings;  # no warnings "exec" is not working
    exec("sleep 10");
    $pm->finish;
}

print "sleep pid is $p\n";
waitpid($p, 0);

For simplicity it's now using sleep. A warning from Perl that "Statement unlikely to be reached" must be suppressed because Perl doesn't realize $pm->start has forked. This should be no warnings "exec" but that's not working so I had to suppress them all.

Cyrus answered 28/12, 2014 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.