Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Check if forked process is dead

by petr999 (Acolyte)
on Mar 02, 2011 at 21:25 UTC ( [id://891098]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I can not distinguish the died fork from alive: killing it with 0 signal always returns 1.
$ perl -Mstrict -wE 'my $pid = fork; if( $pid ){ sleep 3; say kill 0 = +> $pid; waitpid $pid => 0; } else { exit; }' 1 $

Here I wait for 3 seconds, check if the process exists and it does. But waitpid returns immediately which means that process is dead.

UPD.I mean, check for process existence within several seconds as I have many of them for SIGTERM and, later, to SIGKILL those still exist.

Thank you.

Replies are listed 'Best First'.
Re: Check if forked process is dead
by JavaFan (Canon) on Mar 02, 2011 at 21:54 UTC
    No, the process isn't dead. It isn't alive either. It's a zombie (the process has exited, but the parent hasn't waited on it yet). If you read the manual page on kill, you can read that a kill 0 of a zombified process succeeds. (Basically, what kill 0 does is check if 1) the process exists, and 2) is either owned by us, or we are root).

    What you see is expected, and documented behaviour.

Re: Check if forked process is dead
by sundialsvc4 (Abbot) on Mar 02, 2011 at 21:59 UTC

    When you kill a process (in Unix), it enters a “zombie” state so that you can rendezvous with it (via waitpid) and collect its status.   You are obligated to do so.   The process-table entry does not disappear until you wait; hence, until then, it continues to “exist.”

    Do not “pause for a specified interval” after killing a process.   After you have fired your bullet, wait for the corpse to hit the ground (and disappear).   No one likes a roomful of zombies.

      I'd like to know if I can check that process was not terminated by SIGTERM, so I'd SIGKILL it after some seconds. This doesn't work:
      $ perl -Mstrict -MPOSIX -wE 'my $pid = fork; if( $pid ){ kill TERM => +$pid; waitpid $pid => WNOHANG; say kill 0 => $pid; } else { sleep 3; + exit; }' 1 $
      But only 0 instead of WNOHANG shows me that process is ended.
      Can I check if the process is ended in a limited amount of time?
      Should I fork a new process only for a blocking waitpid $pid => 0 particularly?
      Thank you.

        You could inspect what the (non-blocking) waitpid returns. If it's the $pid, the process could be reaped successfully, which means it was no longer running.

        In your case here, you're calling the waitpid just a tad too early, so the preceding kill TERM hasn't been delivered/succeeded yet.  And as the waitpid $pid => WNOHANG couldn't yet reap at that moment, the process still exists as a zombie at the time you call kill 0  (like in your original case).

        Compare:

        Child reacts to SIGTERM:

        #!/usr/bin/perl -wl use strict; use POSIX; my $pid = fork; if ( $pid ) { kill TERM => $pid; # wait for kill TERM to take effect select undef, undef, undef, 0.01; my $reaped = waitpid $pid => WNOHANG; if ($reaped == $pid) { print "already gone."; # <--- } else { print "trying harder..."; kill 9 => $pid; } } else { sleep 3; }

        Child ignores SIGTERM:

        #!/usr/bin/perl -wl use strict; use POSIX; my $pid = fork; if ( $pid ) { # give child some time to set up its $SIG{TERM} handler select undef, undef, undef, 0.01; kill TERM => $pid; select undef, undef, undef, 0.01; my $reaped = waitpid $pid => WNOHANG; if ($reaped == $pid) { print "already gone."; } else { print "trying harder..."; # <--- kill 9 => $pid; } } else { $SIG{TERM} = 'IGNORE'; sleep 3; }

        You cannot avoid race conditions in such a quest ...

Re: Check if forked process is dead
by Eliya (Vicar) on Mar 02, 2011 at 21:42 UTC

    The issue is that unless you have waited on your child process, it's still in the process table, so kill can send signals to it.

      Looks like that.
      How could I know that from the documentation?
      Should I check for the fork existence in a different way?
      My pgrep -P command doesn't see the forked process at the time kill 0 does. This can not be a bug, so what's the salt of a perl feature here?
Re: Check if forked process is dead
by Marshall (Canon) on Mar 02, 2011 at 21:42 UTC
    Looks like to me that you fork a process that starts to do something (like sleep), but then the main process immediately dies. makes a zombie.
      No, forked process is just exits
        I think others have explained this. Basically when the child exits, the OS keeps track of it's exit status until you check it. This is done so that you can find out what happened to it..did it work ok? Was there an error that caused it to abend? If you don't check and clear the status of the child termination, then this status hangs around forever in zombie land. It doesn't consume CPU mips, but it does occupy a place in the process table.
Re: Check if forked process is dead
by Anonymous Monk on Mar 03, 2011 at 02:20 UTC
Re: Check if forked process is dead
by anonymized user 468275 (Curate) on Mar 03, 2011 at 10:12 UTC
    I think the answer to the original question is even simpler:
    if( $pid ){ # we are the parent: sleep 3; say kill 0 => $pid; waitpid $pid => 0; } else { # we are the child: exit; }
    The child immediately does an "exit" - so where's the mystery?

    One world, one people

WNOHANG seem to help
by petr999 (Acolyte) on Mar 02, 2011 at 22:50 UTC
    It works now. Thanks all.
    $ perl -Mstrict -MPOSIX -wE 'my $pid = fork; if( $pid ){ kill TERM => +$pid; foreach( 1..5 ){ sleep 1; waitpid $pid => WNOHANG; my $rv = kil +l 0 => $pid; say $rv; exit unless $rv; } kill KILL => $pid; waitpid $ +pid => 0; } else { BEGIN{ $SIG{TERM}=sub{ say "TERM!"; }; } sleep 3; + exit; }' TERM! 1 1 0 $ perl -Mstrict -MPOSIX -wE 'my $pid = fork; if( $pid ){ kill TERM => +$pid; foreach( 1..3 ){ sleep 1; waitpid $pid => WNOHANG; my $rv = kil +l 0 => $pid; say $rv; exit unless $rv; } kill KILL => $pid; waitpid $ +pid => 0; } else { BEGIN{ $SIG{TERM}=sub{ say "TERM!"; }; } sleep 5; + exit; }' TERM! 1 1 1 $

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://891098]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-06-24 17:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.