Author: radu
Date: Thu Sep  4 04:42:35 2008
New Revision: 941

Modified:
   trunk/Changes
   trunk/qpsmtpd-prefork

Log:
Detect and reset locked shared memory.


Modified: trunk/Changes
==============================================================================
--- trunk/Changes       (original)
+++ trunk/Changes       Thu Sep  4 04:42:35 2008
@@ -1,3 +1,6 @@
+  prefork: detect and reset locked shared memory (based on patch by
+  Diego d'Ambra)
+
   prefork: untaint the value of the --interface option (reported by
   Diego d'Ambra)
 

Modified: trunk/qpsmtpd-prefork
==============================================================================
--- trunk/qpsmtpd-prefork       (original)
+++ trunk/qpsmtpd-prefork       Thu Sep  4 04:42:35 2008
@@ -327,18 +327,26 @@
         if (defined($chld_busy)) {
             info("busy children: $chld_busy");
             $chld_pool = $chld_busy + $idle_children;
+
+            # ensure pool limit is max_children
+            $chld_pool = $max_children if ($chld_pool > $max_children);
+            info(  "children pool: $chld_pool, spawned: "
+                 . scalar(keys %children)
+                 . ", busy: $chld_busy");
         }
+        else {
 
-        # ensure pool limit is max_children
-        $chld_pool = $max_children if ($chld_pool > $max_children);
+            # reset shared memory
+            warn("unable to access shared memory - resetting it");
+            IPC::Shareable->clean_up;
+            my $shmem = shmem($d_port . "qpsmtpd", 1);
+            untie $shmem;
+        }
 
         # spawn children
         for (my $i = scalar(keys %children) ; $i < $chld_pool ; $i++) {
             new_child();    # add to the child pool
         }
-        info(  "children pool: $chld_pool (currently spawned: "
-             . scalar(keys %children)
-             . ")");
 
         # unblock signals
         unblock_signal($sigset);
@@ -530,8 +538,20 @@
         $chld_shmem = &shmem($d_port."qpsmtpd", 0);    #connect to shared 
memory hash
 
         if (tied %{$chld_shmem}) {
-            # perform options
-            (tied %{$chld_shmem})->shlock(LOCK_EX);
+
+            # lock shared memory
+            eval {
+                # ensure that hung shared memory is noticed
+                local $SIG{ALRM} = sub {
+                    die "locking timed out\n";
+                };
+                alarm 15;
+
+                (tied %{$chld_shmem})->shlock(LOCK_EX);
+
+                alarm 0;
+            };
+            die $@ if $@;
 
             # delete
             if ($ref_pid_del) {
@@ -543,6 +563,8 @@
             $$chld_shmem{$pid_add_key} = $pid_add_value if ($pid_add_key);
             # copy
             %{$ref_shmem} = %{$chld_shmem} if ($ref_shmem);
+
+            # check
             if ($check) {
                 # loop through pid list and delete orphaned processes
                 foreach my $pid (keys %{$chld_shmem}) {
@@ -553,13 +575,18 @@
                 }
             }
 
-            # count number of busy children
+            # number of busy children
             $chld_busy = scalar(keys %{$chld_shmem});
+
+            # unlock shared memory
             (tied %{$chld_shmem})->shunlock;
 
             # untie from shared memory
             untie $chld_shmem || die "unable to untie from shared memory";
         }
+        else {
+            die "failed to connect to shared memory";
+        }
     };
 
     # check for error
@@ -669,8 +696,13 @@
         warn("$@");
     }
 
-    # child is now idle again so remove it's pid from shared mem
-    shmem_opt(undef, [$$], undef, undef);
+    # child is now idle again
+    info("disconnect from: $nto_iaddr:$port");
 
-    info("remote host: $ENV{TCPREMOTEIP} left...");
+    # remove pid from shared memory
+    unless (defined(shmem_opt(undef, [$$], undef, undef))) {
+        # exit because parent is down or shared memory is corrupted
+        info("parent seems to be down, going to exit");
+        exit 1;
+    }
 }

Reply via email to