Forkserver tends to die with segmentation faults in the signal handler
as several people on the list noticed. It also sometimes misses the
death of a child. This patch moves the REAPER into the main loop. It now
checks for dead children after each accept and once every second if
there are more then $MAXCONN children. 
This means that zombies hang around until the next client connects.
A bit untidy, but shouldn't be a real problem.
forkserver has been rock-solid for me since this patch.

-- 
   _  | Peter J. Holzer    | Ich sehe nun ein, dass Computer wenig
|_|_) | Sysadmin WSR       | geeignet sind, um sich was zu merken.
| |   | [EMAIL PROTECTED]         |
__/   | http://www.hjp.at/ |    -- Holger Lembke in dan-am
--- qpsmtpd-forkserver.no_sigcld        Tue May 31 21:13:05 2005
+++ qpsmtpd-forkserver  Wed Jun  1 09:07:02 2005
@@ -58,7 +58,6 @@
 my %childstatus = ();
 
 sub REAPER {
-  $SIG{CHLD} = \&REAPER;
   while ( defined(my $chld = waitpid(-1, WNOHANG)) ){
     last unless $chld > 0;
     warn("$$ cleaning up after $chld\n");
@@ -72,7 +71,6 @@
   exit(0);
 }
 
-$SIG{CHLD} = \&REAPER;
 $SIG{INT} = \&HUNTSMAN;
 $SIG{TERM} = \&HUNTSMAN;
 
@@ -129,10 +127,12 @@
 
 
 while (1) {
+  REAPER();
   my $running = scalar keys %childstatus;
   while ($running >= $MAXCONN) { 
     ::log(LOGINFO,"Too many connections: $running >= $MAXCONN.  Waiting one 
second.");
     sleep(1) ;
+    REAPER();
     $running = scalar keys %childstatus;
   }
     my $hisaddr = accept(my $client, $server);
@@ -151,6 +151,8 @@
         # If we for-loop directly over values %childstatus, a SIGCHLD
         # can call REAPER and slip $rip out from under us.  Causes
         # "Use of freed value in iteration" under perl 5.8.4.
+       #
+       # REAPER isn't a signal handler anymore, so this can't happen.
         my @rip = values %childstatus;
         foreach my $rip (@rip) {
           ++$num_conn if (defined $rip && $rip eq $iaddr);

Attachment: pgp2tDQfNatTt.pgp
Description: PGP signature

Reply via email to