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

AIX and Perl's SIGCHLD hates me and for my application I can't install install the signal handler without some very quirky problems in my application so I need another way besides wait() to know if my reader program was successful or not. I have some glue code that takes some options and opens up some reader programs (that I can't modify). Then it copies the stdout of the reader to perl's stdout like so.
open(INPIPE,"$reader_prog $options |") or die('Cant open reader'); while($bytes = read(INPIPE,$buffer,32768)){ print $buffer; }
I found that if it doesn't read any data I read 0 bytes from INPIPE. It could be that the reader will give me 0 bytes in a normal situation so I can't use the amount of data to determine success or not. Since the reader program was found but had some other error the die isn't triggered either. Is there any other way than SIGCHLD to get the reader's RC or know if it failed? Any other tricky ways I can infer if it failed or completed successfully? Stderr has to be left alone to be collected outside of my perl script. Any one have any experience working around broken SIGCHLD behavior?

Replies are listed 'Best First'.
Re: Children and return codes
by pc88mxer (Vicar) on Jan 10, 2008 at 23:23 UTC
    You while loop will terminate when you've reached EOF on the pipe or there was an error. In the first case $bytes will be 0 and the second it'll be undef. To get the exit status of the child, you don't need to install a SIGCHLD handler. Just waitpid for the child process to terminate and check $?. So, here's one way to get the status w/o using SIGCHLD:
    use POSIX ":sys_wait_h"; my $pid = open(INPIPE, "$reader_prog $options |") or die "open failed: + $!"; while ($bytes = read(INPIPE, $bugger, 32768)) { print $buffer; } if (!defined($bytes)) { print "read error: $!\n"; } my $kid = waitpid($pid, WNOHANG); unless ($kid == $pid) { print "child process $pid is still running\n"; print "trying close\n"; close(INPIPE); print "child status is $?\n"; } else { print "child process $pid reaped, status is: $?\n"; }
    Notes:
    • If the child terminates, the pipe will be closed, and eventually you'll get EOF when trying to read from it.
    • Be aware that the child can close the pipe but continue to run.
    • When using read, getting a read length of 0 means that the pipe was closed. read will wait for data to become present if none is available at the time (i.e. it will block).
    • To check if data is available to be read from the pipe, use select.
    • Using close will close the parent's end of the pipe and wait for the child to terminate. In this case, the parent executing close will cause the child to get a SIGPIPE error when it tries to write to the pipe, and this usually will cause the child to terminate.
Re: Children and return codes
by bot403 (Beadle) on Jan 11, 2008 at 15:11 UTC
    Doh! Thats just the simple answer I knew I was overlooking. Thanks!