Remove duplicate assignment to PL_eval_root in Perl_create_eval_scope
[p5sagit/p5-mst-13.2.git] / pod / perlipc.pod
index 671da85..4061dd1 100644 (file)
@@ -309,7 +309,7 @@ There were two things you could do, knowing this: be paranoid or be
 pragmatic.  The paranoid approach was to do as little as possible in your
 signal handler.  Set an existing integer variable that already has a
 value, and return.  This doesn't help you if you're in a slow system call,
-which will just restart.  That means you have to C<die> to longjump(3) out
+which will just restart.  That means you have to C<die> to longjmp(3) out
 of the handler.  Even this is a little cavalier for the true paranoiac,
 who avoids C<die> in a handler because the system I<is> out to get you.
 The pragmatic approach was to say "I know the risks, but prefer the
@@ -915,67 +915,91 @@ go back to service a new client.
     my $paddr;
 
     use POSIX ":sys_wait_h";
+    use Errno;
+
     sub REAPER {
-       my $child;
-        while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
-           logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
-       }
-       $SIG{CHLD} = \&REAPER;  # loathe sysV
+        local $!;   # don't let waitpid() overwrite current error
+        while ((my $pid = waitpid(-1,WNOHANG)) > 0 && WIFEXITED($?)) {
+            logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
+        }
+        $SIG{CHLD} = \&REAPER;  # loathe sysV
     }
 
     $SIG{CHLD} = \&REAPER;
 
-    for ( $waitedpid = 0;
-         ($paddr = accept(Client,Server)) || $waitedpid;
-         $waitedpid = 0, close Client)
-    {
-       next if $waitedpid and not $paddr;
-       my($port,$iaddr) = sockaddr_in($paddr);
-       my $name = gethostbyaddr($iaddr,AF_INET);
-
-       logmsg "connection from $name [",
-               inet_ntoa($iaddr), "]
-               at port $port";
-
-       spawn sub {
-           $|=1;
-           print "Hello there, $name, it's now ", scalar localtime, $EOL;
-           exec '/usr/games/fortune'           # XXX: `wrong' line terminators
-               or confess "can't exec fortune: $!";
-       };
-
+    while(1) {
+        $paddr = accept(Client, Server) || do {
+            # try again if accept() returned because a signal was received
+            next if $!{EINTR};
+            die "accept: $!";
+        };
+        my ($port, $iaddr) = sockaddr_in($paddr);
+        my $name = gethostbyaddr($iaddr, AF_INET);
+
+        logmsg "connection from $name [",
+               inet_ntoa($iaddr),
+               "] at port $port";
+
+        spawn sub {
+            $|=1;
+            print "Hello there, $name, it's now ", scalar localtime, $EOL;
+            exec '/usr/games/fortune'       # XXX: `wrong' line terminators
+                or confess "can't exec fortune: $!";
+        };
+        close Client;
     }
 
     sub spawn {
-       my $coderef = shift;
+        my $coderef = shift;
 
-       unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
-           confess "usage: spawn CODEREF";
-       }
+        unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
+            confess "usage: spawn CODEREF";
+        }
 
-       my $pid;
-       if (!defined($pid = fork)) {
-           logmsg "cannot fork: $!";
-           return;
-       } elsif ($pid) {
-           logmsg "begat $pid";
-           return; # I'm the parent
-       }
-       # else I'm the child -- go spawn
+        my $pid;
+        if (! defined($pid = fork)) {
+            logmsg "cannot fork: $!";
+            return;
+        } 
+        elsif ($pid) {
+            logmsg "begat $pid";
+            return; # I'm the parent
+        }
+        # else I'm the child -- go spawn
 
-       open(STDIN,  "<&Client")   || die "can't dup client to stdin";
-       open(STDOUT, ">&Client")   || die "can't dup client to stdout";
-       ## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
-       exit &$coderef();
+        open(STDIN,  "<&Client")   || die "can't dup client to stdin";
+        open(STDOUT, ">&Client")   || die "can't dup client to stdout";
+        ## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
+        exit &$coderef();
     }
 
-This server takes the trouble to clone off a child version via fork() for
-each incoming request.  That way it can handle many requests at once,
-which you might not always want.  Even if you don't fork(), the listen()
-will allow that many pending connections.  Forking servers have to be
-particularly careful about cleaning up their dead children (called
-"zombies" in Unix parlance), because otherwise you'll quickly fill up your
-process table.
+This server takes the trouble to clone off a child version via fork()
+for each incoming request.  That way it can handle many requests at
+once, which you might not always want.  Even if you don't fork(), the
+listen() will allow that many pending connections.  Forking servers
+have to be particularly careful about cleaning up their dead children
+(called "zombies" in Unix parlance), because otherwise you'll quickly
+fill up your process table.  The REAPER subroutine is used here to
+call waitpid() for any child processes that have finished, thereby
+ensuring that they terminate cleanly and don't join the ranks of the
+living dead.
+
+Within the while loop we call accept() and check to see if it returns
+a false value.  This would normally indicate a system error that needs
+to be reported.  However the introduction of safe signals (see
+L</Deferred Signals (Safe Signals)> above) in Perl 5.7.3 means that
+accept() may also be interrupted when the process receives a signal.
+This typically happens when one of the forked sub-processes exits and
+notifies the parent process with a CHLD signal.  
+
+If accept() is interrupted by a signal then $! will be set to EINTR.
+If this happens then we can safely continue to the next iteration of
+the loop and another call to accept().  It is important that your
+signal handling code doesn't modify the value of $! or this test will
+most likely fail.  In the REAPER subroutine we create a local version
+of $! before calling waitpid().  When waitpid() sets $! to ECHILD (as
+it inevitably does when it has no more children waiting), it will
+update the local copy leaving the original unchanged.
 
 We suggest that you use the B<-T> flag to use taint checking (see L<perlsec>)
 even if we aren't running setuid or setgid.  This is always a good idea
@@ -1012,7 +1036,7 @@ differ from the system on which it's being run:
        my $rtime = '    ';
        read(SOCKET, $rtime, 4);
        close(SOCKET);
-       my $histime = unpack("N", $rtime) - $SECS_of_70_YEARS ;
+       my $histime = unpack("N", $rtime) - $SECS_of_70_YEARS;
        printf "%8d %s\n", $histime - time, ctime($histime);
     }
 
@@ -1516,7 +1540,7 @@ with TCP, you'd have to use a different socket handle for each host.
        ($hispaddr = recv(SOCKET, $rtime, 4, 0))        || die "recv: $!";
        ($port, $hisiaddr) = sockaddr_in($hispaddr);
        $host = gethostbyaddr($hisiaddr, AF_INET);
-       $histime = unpack("N", $rtime) - $SECS_of_70_YEARS ;
+       $histime = unpack("N", $rtime) - $SECS_of_70_YEARS;
        printf "%-12s ", $host;
        printf "%8d %s\n", $histime - time, scalar localtime($histime);
        $count--;
@@ -1537,10 +1561,10 @@ you weren't wanting it to.
 
 Here's a small example showing shared memory usage.
 
-    use IPC::SysV qw(IPC_PRIVATE IPC_RMID S_IRWXU);
+    use IPC::SysV qw(IPC_PRIVATE IPC_RMID S_IRUSR S_IWUSR);
 
     $size = 2000;
-    $id = shmget(IPC_PRIVATE, $size, S_IRWXU) || die "$!";
+    $id = shmget(IPC_PRIVATE, $size, S_IRUSR|S_IWUSR) || die "$!";
     print "shm key $id\n";
 
     $message = "Message #1";
@@ -1615,9 +1639,9 @@ which is included with Perl starting from Perl 5.005.
 
 A small example demonstrating SysV message queues:
 
-    use IPC::SysV qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRWXU);
+    use IPC::SysV qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRUSR S_IWUSR);
 
-    my $id = msgget(IPC_PRIVATE, IPC_CREAT | S_IRWXU);
+    my $id = msgget(IPC_PRIVATE, IPC_CREAT | S_IRUSR | S_IWUSR);
 
     my $sent = "message";
     my $type_sent = 1234;