From: Maik Hentsche Date: Tue, 15 Jun 2010 15:19:41 +0000 (+0200) Subject: Attempt at improving the perlipc docs X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=0a18a49b281a5a76e75de77e45ee27ad1b807bb2;p=p5sagit%2Fp5-mst-13.2.git Attempt at improving the perlipc docs --- diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod index f3e65b4..d528e2f 100644 --- a/pod/perlfunc.pod +++ b/pod/perlfunc.pod @@ -6747,6 +6747,9 @@ When C's arguments are executed indirectly by the shell, results and return codes are subject to its quirks. See L and L for details. +Since C does a C and C it may affect a C +handler. See L for details. + =item syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET X @@ -7606,6 +7609,9 @@ and C<${^CHILD_ERROR_NATIVE}>. Note that a return value of C<-1> could mean that child processes are being automatically reaped, as described in L. +If you use wait in your handler for $SIG{CHLD} it may accidently wait for the +child created by qx() or system(). See L for details. + =item waitpid PID,FLAGS X diff --git a/pod/perlipc.pod b/pod/perlipc.pod index 4f6c0f0..8d9ea97 100644 --- a/pod/perlipc.pod +++ b/pod/perlipc.pod @@ -150,7 +150,43 @@ or better still: $SIG{CHLD} = \&REAPER; # do something that forks... -Signal handling is also used for timeouts in Unix, While safely +Note: qx(), system() and some modules for calling external commands do a +fork() and wait() for the result. Thus, your signal handler (REAPER in the +example) will be called. Since wait() was already called by system() or qx() +the wait() in the signal handler will not see any more zombies and therefore +block. + +The best way to prevent this issue is to use waitpid, as in the following +example: + + use POSIX ":sys_wait_h"; # for nonblocking read + + my %children; + + $SIG{CHLD} = sub { + # don't change $! and $? outside handler + local ($!,$?); + my $pid = waitpid(-1, WNOHANG); + return if $pid == -1; + return unless defined $children{$pid}; + delete $children{$pid}; + cleanup_child($pid, $?); + }; + + while (1) { + my $pid = fork(); + if ($pid == 0) { + # ... + exit 0; + } else { + $children{$pid}=1; + # ... + system($command); + # ... + } + } + +Signal handling is also used for timeouts in Unix. While safely protected within an C block, you set a signal handler to trap alarm signals and then schedule to have one delivered to you in some number of seconds. Then try your blocking operation, clearing the alarm