Attempt at improving the perlipc docs
Maik Hentsche [Tue, 15 Jun 2010 15:19:41 +0000 (17:19 +0200)]
pod/perlfunc.pod
pod/perlipc.pod

index f3e65b4..d528e2f 100644 (file)
@@ -6747,6 +6747,9 @@ When C<system>'s arguments are executed indirectly by the shell,
 results and return codes are subject to its quirks.
 See L<perlop/"`STRING`"> and L</exec> for details.
 
+Since C<system> does a C<fork> and C<wait> it may affect a C<SIGCHLD>
+handler. See L<perlipc> for details.
+
 =item syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET
 X<syswrite>
 
@@ -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<perlipc>.
 
+If you use wait in your handler for $SIG{CHLD} it may accidently wait for the
+child created by qx() or system(). See L<perlipc> for details.
+
 =item waitpid PID,FLAGS
 X<waitpid>
 
index 4f6c0f0..8d9ea97 100644 (file)
@@ -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<eval{}> 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