http://qs321.pair.com?node_id=197500

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

I have a process that runs as a daemon forking off child processes when requests come in. To control zombies I have the standard
# Install signal handler for child processes $SIG{'CHLD'} = sub { while (waitpid(-1,WNOHANG) > 0) {} };
However, the child processes then have to make a system call and I need to trap the exit code eg..
my $res = system $cmd, $arg; unless ($res == 0) { ... }
$? now contains -1 and $! 'No child processes', I understand that this is because of my $SIG{'CHLD'} handler. But how can I get the true exit code and message? I've tried 'local $SIG{'CHLD'} = '' prior to the sys call and that seems to work but looks very clumsy.

What is the best way to get at the exit code?

Replies are listed 'Best First'.
Re: No child processes
by RMGir (Prior) on Sep 13, 2002 at 11:29 UTC
    If local $SIG{CHLD} is clumsy, why not hide it?
    # or whatever name you like, my_system, systemx, # safe_system, sig_system... sub wrapped_system { # Use local signal handler so global handler # does not result in bad values in $? and $! local $SIG{CHLD}=''; return system @_; }
    If you run into this problem in more than one place in your code, moving this into a subroutine would make all that much more sense.
    --
    Mike
Re: No child processes
by slife (Scribe) on Sep 13, 2002 at 13:22 UTC

    If you are really determined that you don't want to un-set your CHLD signal handler, you need to bear in mind two things:

    i) your 'standard' handler is throwing away the child pid and return code values and
    ii) system() is, in effect, shorthand for the traditional UNIX fork/exec/wait idiom.

    You may, therefore, want to set the signal handler to do something useful like:
    my %pid; $SIG{CHLD} = sub { while((my $kid = waitpid(-1,WNOHANG))>0 ) { warn "PID $kid returned $?"; } };

    (this is based Lincoln Stein's 'Network Programming with Perl' p305).
    .....

    and replace $res = system @args;
    with exec @args;

    Though, you will need to consider the usual caveats regarding signal handlers in perls prior to 5.8.0 ...

Re: No child processes
by PodMaster (Abbot) on Sep 13, 2002 at 11:14 UTC
    Why is local $SIG{CHLD}; clumsy?

    ____________________________________________________
    ** The Third rule of perl club is a statement of fact: pod is sexy.

Re: No child processes
by Jonathan (Curate) on Sep 13, 2002 at 13:36 UTC
    Thanks for all replies - duly up-voted.
    I raised the question because I felt I'd missed a subtle finesse. Guess I haven't apologies extended.
Re: No child processes
by Anonymous Monk on Jun 07, 2018 at 15:33 UTC
    local $SIG{CHLD} = sub { local ($!, $?); while (waitpid(-1, WNOHANG) > 0) {} };
    seems to fix this issue