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. | [reply] |
Re: Check if forked process is dead
by locked_user 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. | [reply] [d/l] |
|
|
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;
}
| [reply] [d/l] [select] |
|
|
|
|
| |
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.
| [reply] |
|
|
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?
| [reply] |
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. | [reply] |
|
|
No, forked process is just exits
| [reply] |
|
|
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.
| [reply] |
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?
| [reply] [d/l] |
Re: Check if forked process is dead
by Anonymous Monk on Mar 03, 2011 at 02:20 UTC
|
| [reply] |
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
$
| [reply] [d/l] |