Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re: Detecting when a child process is killed unexpectedly

by gmargo (Hermit)
on Oct 17, 2009 at 06:17 UTC ( [id://801710]=note: print w/replies, xml ) Need Help??


in reply to Detecting when a child process is killed unexpectedly

Two main problems that I see:
1) A faulty assumption that the process exit code covers the 'death by signal' case.
2) Missing parentheses on the exists statements, giving the wrong precedence.

Here is code which covers all cases hopefully:

#!/usr/bin/perl use strict; use warnings; use diagnostics; use POSIX ":sys_wait_h"; use Data::Dumper; my %child_status; sub reaper { my $child; while (($child=waitpid(-1,WNOHANG))>0) { # See waitpid(2) and POSIX(3perl) my $status = $?; my $wifexited = WIFEXITED($status); my $wexitstatus = $wifexited ? WEXITSTATUS($status) : undef; my $wifsignaled = WIFSIGNALED($status); my $wtermsig = $wifsignaled ? WTERMSIG($status) : undef; my $wifstopped = WIFSTOPPED($status); my $wstopsig = $wifstopped ? WSTOPSIG($status) : undef; $child_status{$child} = { status => $status, wifexited => $wifexited, wexitstatus => $wexitstatus, wifsignaled => $wifsignaled, wtermsig => $wtermsig, wifstopped => $wifstopped, wstopsig => $wstopsig, }; print STDERR "reaper: reaped child=$child" ." status=$status" ." wifexited=$wifexited" ." wexitstatus=".(defined($wexitstatus) ? $wexitstatus : " +undef") ." wifsignaled=$wifsignaled" ." wtermsig=".(defined($wtermsig) ? $wtermsig : "undef") ." wifstopped=$wifstopped" ." wstopsig=".(defined($wstopsig) ? $wstopsig : "undef") ."\n"; } } sub copy { my $file = shift; my $dir = shift; local $SIG{CHLD} = \&reaper; my $reader_pid = open( my $reader, '-|' ); if ($reader_pid) { print STDERR "copy: spawned reader child=\"$reader_pid\"\n"; } else { exec '/bin/cat', $file; exit; } my $writer_pid; if ($writer_pid = fork()) { print STDERR "copy: spawned writer child=\"$writer_pid\"\n"; } else { chdir($dir); open( STDIN, "<&=" . fileno($reader) ); exec '/bin/tar', '-x', '-p', '-f', '-'; exit; } while (1) { sleep 1; next if !%child_status; foreach my $pid ($reader_pid, $writer_pid) { if (exists $child_status{$pid}) { my $st = $child_status{$pid}; # check for non-zero exit status # check for death by signal if (($st->{wifexited} && $st->{wexitstatus} != 0) || $st->{wifsignaled}) { print Dumper \%child_status; die "failed ".($pid == $writer_pid ? "tar" : "rea +der"); } } } if (exists($child_status{$writer_pid}) && exists($child_status +{$reader_pid})) { last; } } } copy("/home/tmp/quotes.tar","."); exit 0;

Replies are listed 'Best First'.
Precedence/Prototypes - Re^2: Detecting when a child process is killed unexpectedly
by jakobi (Pilgrim) on Oct 17, 2009 at 10:05 UTC
    > 1) A faulty assumption that the process exit code covers the 'death by signal' case.

    SIGSTOP e.g. is indeed something to skip later-on in detecting when to terminate.

    But there's still an issue: ignored child state changes must be either ignored in the reaper or in the loop exit condition, otherwise we exit the loop on e.g. SIGSTOP as well.

    > 2) Missing parentheses on the exists statements, giving the wrong precedence.

    Here I got curious, as the test script behaved as expected when I killed my sleep child processes with zap sleep.3.

    perl -MO=Deparse -e '%a=("a",1,"b",2); print "ok" if exists $a{a} && 1 ++exists $a{b}' # (%a) = ('a', 1, 'b', 2); # print 'ok' if exists $a{'a'} and 1 + exists($a{'b'}); # NOTE above interesting and _misleading_ choice of parens, _plus_ tra +nslation to 'and' perl -MO=Deparse -e '%a=("a",1,"b",2); print "ok" if exists($a{a} && 1 ++exists $a{b})' # exists argument is not a HASH or ARRAY element at -e line 1. # NOTE same error of course w/o Deparse, also when I move ')' behind ' +1'.

    While 'and' surely makes the condition more readable, it doesn't look like '&&' leads to an unintended precedence. Which you'd normally expect with '&&' (when using it yourself intentionally). Why this? ->

    perl -MO=Deparse -e 'sub f {warn join "\n",@_,"",""};%a=("a",1,"b",2); + print "ok" if f $a{a} && 5+f $a{b}' # print 'ok' if f $a{'a'} && 5 + f($a{'b'}); # output 2 6 (* with sub f ($), it's 1 2) perl -MO=Deparse -e 'sub f {warn join "\n",@_,"",""};%a=("a",1,"b",2); + print "ok" if f($a{a} && 5+f $a{b})' # print 'ok' if f $a{'a'} && 5 + f($a{'b'}); # output 5 2 perl -MO=Deparse -e 'sub f {warn join "\n",@_,"",""};%a=("a",1,"b",2); + print "ok" if f($a{a} && 5)+f $a{b}' # print 'ok' if f($a{'a'} && 5) + f($a{'b'}); perl -e 'sub f {warn join "\n",@_,"",""};%a=("a",1,"b",2); print "ok" +if f($a{a}) && 5+f($a{b})' # output 1 2 perl -e 'sub f {warn join "\n",@_,"",""};%a=("a",1,"b",2); print "ok" +if f $a{a} and 5+f $a{b}' # output 1 2

    (I'd naively expected Deparse to be a bit more explicit in its rephrasing. Anyway:)

    After reading man perlop, exists() is a named unary operator, and thus has precedence over both '&&' and 'and'. The function f in contrast is a 'list operator (rightward)', with a precedence lower than '&&'.

    So the precedence in the statement was correct. And considering the three of us, this loop exit statement is well on it's way to become a future maintenance trap :).

    Suggestion: Consider replacing '&&' with the more normal/readable 'and'.

    Note that using parens is still required to protect against e.g. prototypes overturning naive precedence expectations wrt e.g. comparison operators:

    f 3 >= 5
    What is the argument here to a previous sub f?
    And in case of sub f($)?
    And what about &f 3 >= 5 for both cases?

    Perlish prototypes != C prototypes in use and semantics: (tye)Re: A question of style, &f vs f(), Gratuitous use of Perl Prototypes and finally USAGE OF Prototype.

    /me leaves to fetch an Arkansas stone and some honing oil in order to remove the embarassing nicks out of /my paranoia.

      Regarding SIGSTOP (& SIGCONT), they are not an issue since waitpid() will only return stop/cont indications if called with the WUNTRACED argument. I should not have checked WIFSTOPPED at all.

      Regarding the usage of "exists", you are quite correct, and I am humbled.

        Ah, don't be. Au contraire: We both found some surprises and learned something to augment our hubris with (Perl Programmer Virtue #3).

        Now open: Vote for the [public motion] to list Paranoia as Perl Virtue #4

        :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://801710]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2026-01-13 21:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What's your view on AI coding assistants?





    Results (118 votes). Check out past polls.

    Notices?
    hippoepoptai's answer Re: how do I set a cookie and redirect was blessed by hippo!
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.