=== modified file 'configure.in'
--- configure.in	2009-04-30 11:51:29 +0000
+++ configure.in	2009-05-03 10:43:21 +0000
@@ -65,6 +65,10 @@
 AC_LIBTOOL_DLOPEN
 if test $use_loadable_modules = yes;
 then
+    dnl Debian libtool 2.2.6 is broken.
+    top_build_prefix=${top_build_dir}
+    _AC_HAVE_TOP_BUILD_PREFIX=0
+
     AC_LIBLTDL_CONVENIENCE(lib/libLtdl)
 fi
 AC_PROG_LIBTOOL

=== modified file 'src/helper.cc'
--- src/helper.cc	2009-04-17 22:09:22 +0000
+++ src/helper.cc	2009-05-05 12:09:27 +0000
@@ -68,6 +68,30 @@
 static void helperStatefulServerKickQueue(helper_stateful_server * srv);
 static bool helperStartStats(StoreEntry *sentry, void *hlp, const char *label);
 
+/**
+ * Abort reading from this helper immediately.
+ *
+ * This is a sharp short closure for the helper which may be used
+ * for quick closure or error aborting.
+ * Any pending requests are abandoned.
+ *
+ * It's used during helprShutdown, but that is just graceful enough
+ * to schedule the close and wait for existing queues to drain.
+ */
+static void helperDoAbort(helper_server * srv);
+static void helperStatefulDoAbort(helper_stateful_server * srv);
+
+/**
+ * Graceful closure of the helper.
+ * Write socket is closed and helper marked as closing so that
+ * further requests are not queued.
+ *
+ * Pending queued items are currently abandoned (need to fix that),
+ * but requests already sent to the helper are waited for
+ * and the sockets only fully closed when none remain to receive back.
+ */
+static void helperDoGracefulClose(helper_server * srv);
+static void helperStatefulDoGracefulClose(helper_stateful_server * srv);
 
 CBDATA_TYPE(helper);
 CBDATA_TYPE(helper_server);
@@ -419,7 +443,7 @@
             if (srv->flags.reserved == S_HELPER_RESERVED)
                 continue;
 
-            if (!srv->flags.shutdown)
+            if (srv->flags.shutdown || srv->flags.closing)
                 continue;
 
             if ((hlp->IsAvailable != NULL) && (srv->data != NULL) &&
@@ -587,7 +611,7 @@
     storeAppendPrintf(sentry, "   B = BUSY\n");
     storeAppendPrintf(sentry, "   W = WRITING\n");
     storeAppendPrintf(sentry, "   C = CLOSING\n");
-    storeAppendPrintf(sentry, "   S = SHUTDOWN\n");
+    storeAppendPrintf(sentry, "   S = SHUTDOWN PENDING\n");
 }
 
 void
@@ -644,16 +668,15 @@
     storeAppendPrintf(sentry, "   B = BUSY\n");
     storeAppendPrintf(sentry, "   C = CLOSING\n");
     storeAppendPrintf(sentry, "   R = RESERVED or DEFERRED\n");
-    storeAppendPrintf(sentry, "   S = SHUTDOWN\n");
+    storeAppendPrintf(sentry, "   S = SHUTDOWN PENDING\n");
     storeAppendPrintf(sentry, "   P = PLACEHOLDER\n");
 }
 
-void
+int
 helperShutdown(helper * hlp)
 {
     dlink_node *link = hlp->servers.head;
 #ifdef _SQUID_MSWIN_
-
     HANDLE hIpc;
     pid_t pid;
     int no;
@@ -669,65 +692,31 @@
             continue;
         }
 
-        hlp->n_active--;
-        assert(hlp->n_active >= 0);
-
-        srv->flags.shutdown = 1;	/* request it to shut itself down */
+        srv->flags.shutdown = 1;	/* request it to shut itself down at next available moment */
 
         if (srv->flags.closing) {
-            debugs(84, 3, "helperShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is CLOSING.");
+            debugs(84, 3, "helperShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is CLOSING. Shutdown pending.");
             continue;
         }
 
         if (srv->stats.pending) {
-            debugs(84, 3, "helperShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is BUSY.");
+            debugs(84, 1, "helperShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is BUSY. Shutdown delayed.");
             continue;
         }
 
-        srv->flags.closing = 1;
-#ifdef _SQUID_MSWIN_
-
-        hIpc = srv->hIpc;
-        pid = srv->pid;
-        no = srv->index + 1;
-        shutdown(srv->wfd, SD_BOTH);
-#endif
-
-        debugs(84, 3, "helperShutdown: " << hlp->id_name << " #" << srv->index + 1 << " shutting down.");
-        /* the rest of the details is dealt with in the helperServerFree
-         * close handler
-         */
-        comm_close(srv->rfd);
-#ifdef _SQUID_MSWIN_
-
-        if (hIpc) {
-            if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
-                getCurrentTime();
-                debugs(84, 1, "helperShutdown: WARNING: " << hlp->id_name <<
-                       " #" << no << " (" << hlp->cmdline->key << "," <<
-                       (long int)pid << ") didn't exit in 5 seconds");
-
-            }
-
-            CloseHandle(hIpc);
-        }
-
-#endif
-
+        hlp->n_active--;
+        assert(hlp->n_active >= 0);
+        helperDoAbort(srv);
     }
+
+    return hlp->n_active;
 }
 
-void
+int
 helperStatefulShutdown(statefulhelper * hlp)
 {
     dlink_node *link = hlp->servers.head;
     helper_stateful_server *srv;
-#ifdef _SQUID_MSWIN_
-
-    HANDLE hIpc;
-    pid_t pid;
-    int no;
-#endif
 
     while (link) {
         srv = (helper_stateful_server *)link->data;
@@ -738,63 +727,118 @@
             continue;
         }
 
-        hlp->n_active--;
-        assert(hlp->n_active >= 0);
         srv->flags.shutdown = 1;	/* request it to shut itself down */
 
+        if (srv->flags.closing) {
+            debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is CLOSING.");
+            continue;
+        }
+
         if (srv->flags.busy) {
-            debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is BUSY.");
-            continue;
-        }
-
-        if (srv->flags.closing) {
-            debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is CLOSING.");
+            debugs(84, 1, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is BUSY.");
             continue;
         }
 
         if (srv->flags.reserved != S_HELPER_FREE) {
-            debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is RESERVED.");
+            debugs(84, 1, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " is RESERVED.");
             continue;
         }
 
         if (srv->deferred_requests) {
-            debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " has DEFERRED requests.");
+            debugs(84, 1, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " has DEFERRED requests.");
             continue;
         }
 
-        srv->flags.closing = 1;
-#ifdef _SQUID_MSWIN_
-
-        hIpc = srv->hIpc;
-        pid = srv->pid;
-        no = srv->index + 1;
-        shutdown(srv->wfd, SD_BOTH);
-#endif
-
-        debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " shutting down.");
-
-        /* the rest of the details is dealt with in the helperStatefulServerFree
-         * close handler
-         */
-        comm_close(srv->rfd);
-#ifdef _SQUID_MSWIN_
-
-        if (hIpc) {
-            if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
-                getCurrentTime();
-                debugs(84, 1, "helperShutdown: WARNING: " << hlp->id_name <<
-                       " #" << no << " (" << hlp->cmdline->key << "," <<
-                       (long int)pid << ") didn't exit in 5 seconds");
-            }
-
-            CloseHandle(hIpc);
-        }
-
-#endif
-
-    }
-}
-
+        hlp->n_active--;
+        assert(hlp->n_active >= 0);
+        helperStatefulDoAbort(srv);
+    }
+
+    return hlp->n_active;
+}
+
+
+void
+helperDoAbort(helper_server *srv)
+{
+#ifdef _SQUID_MSWIN_
+    HANDLE hIpc = srv->hIpc;
+    pid_t pid = srv->pid;
+    int no = srv->index + 1;
+    shutdown(srv->wfd, SD_BOTH);
+#endif
+
+    debugs(84, 3, "helperDoClose: " << hlp->id_name << " #" << srv->index + 1 << " shutting down.");
+
+    /* the rest of the details is dealt with in the helperServerFree
+     * close handler
+     */
+    srv->flags.closing = 1;
+    comm_close(srv->rfd);
+
+#ifdef _SQUID_MSWIN_
+    if (hIpc) {
+        if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
+            getCurrentTime();
+            debugs(84, 1, "helperDoClose: WARNING: " << hlp->id_name <<
+                   " #" << no << " (" << hlp->cmdline->key << "," <<
+                   (long int)pid << ") didn't exit in 5 seconds");
+        }
+        CloseHandle(hIpc);
+    }
+#endif
+}
+
+// TODO merge the stateful and non-stateful close functions into one. They are exactly identical.
+void
+helperStatefulDoAbort(helper_stateful_server *srv)
+{
+#ifdef _SQUID_MSWIN_
+    HANDLE hIpc = srv->hIpc;
+    pid_t pid = srv->pid;
+    int no = srv->index + 1;
+    shutdown(srv->wfd, SD_BOTH);
+#endif
+
+    debugs(84, 3, "helperStatefulDoClose: " << hlp->id_name << " #" << srv->index + 1 << " shutting down.");
+
+    /* the rest of the details is dealt with in the helperStatefulServerFree
+     * close handler
+     */
+    srv->flags.closing = 1;
+    comm_close(srv->rfd);
+
+#ifdef _SQUID_MSWIN_
+    if (hIpc) {
+        if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
+            getCurrentTime();
+            debugs(84, 1, "helperStatefulDoClose: WARNING: " << hlp->id_name <<
+                   " #" << no << " (" << hlp->cmdline->key << "," <<
+                   (long int)pid << ") didn't exit in 5 seconds");
+        }
+        CloseHandle(hIpc);
+    }
+#endif
+}
+
+void
+helperDoGracefulClose(helper_server *srv)
+{
+    int wfd = srv->wfd;
+    srv->wfd = -1;
+    srv->flags.closing=1;
+    comm_close(wfd);
+}
+
+// TODO merge the stateful and non-stateful close functions into one. They are exactly identical.
+void
+helperStatefulDoGracefulClose(helper_stateful_server *srv)
+{
+    int wfd = srv->wfd;
+    srv->wfd = -1;
+    srv->flags.closing=1;
+    comm_close(wfd);
+}
 
 helper *
 helperCreate(const char *name)
@@ -892,8 +936,9 @@
 
     safe_free(srv->requests);
 
+    /* TODO: walk the local queue of requests and carry them all out with error results ? */
     if (srv->wfd != srv->rfd && srv->wfd != -1)
-        comm_close(srv->wfd);
+        helperDoGracefulClose(srv);
 
     dlinkDelete(&srv->link, &hlp->servers);
 
@@ -954,9 +999,9 @@
         srv->request = NULL;
     }
 
-    /* TODO: walk the local queue of requests and carry them all out */
+    /* TODO: walk the local queue of requests and carry them all out with error results ? */
     if (srv->wfd != srv->rfd && srv->wfd != -1)
-        comm_close(srv->wfd);
+        helperStatefulDoGracefulClose(srv);
 
     dlinkDelete(&srv->link, &hlp->servers);
 
@@ -1011,8 +1056,7 @@
         if (len < 0)
             debugs(84, 1, "helperHandleRead: FD " << fd << " read: " << xstrerror());
 
-        comm_close(fd);
-
+        helperDoClose(srv);
         return;
     }
 
@@ -1080,17 +1124,13 @@
             debugs(84, 1, "helperHandleRead: unexpected reply on channel " <<
                    i << " from " << hlp->id_name << " #" << srv->index + 1 <<
                    " '" << srv->rbuf << "'");
-
         }
 
         srv->roffset -= (t - srv->rbuf);
         memmove(srv->rbuf, t, srv->roffset + 1);
 
         if (srv->flags.shutdown) {
-            int wfd = srv->wfd;
-            srv->wfd = -1;
-            srv->flags.closing=1;
-            comm_close(wfd);
+            helperDoGracefulClose(srv);
             return;
         } else
             helperKickQueue(hlp);
@@ -1123,8 +1163,7 @@
         if (len < 0)
             debugs(84, 1, "helperStatefulHandleRead: FD " << fd << " read: " << xstrerror());
 
-        comm_close(fd);
-
+        helperStatefulDoClose(srv);
         return;
     }
 
@@ -1219,10 +1258,8 @@
         if (srv->flags.shutdown
                 && srv->flags.reserved == S_HELPER_FREE
                 && !srv->deferred_requests) {
-            int wfd = srv->wfd;
-            srv->wfd = -1;
-            srv->flags.closing=1;
-            comm_close(wfd);
+            
+            helperStatefulDoGracefulClose(srv);
         } else {
             if (srv->queue.head)
                 helperStatefulServerKickQueue(srv);
@@ -1381,7 +1418,7 @@
         if (selected && selected->stats.pending <= srv->stats.pending)
             continue;
 
-        if (srv->flags.shutdown)
+        if (srv->flags.shutdown || srv->flags.closing)
             continue;
 
         if (!srv->stats.pending)
@@ -1424,7 +1461,7 @@
         if (srv->flags.reserved == S_HELPER_RESERVED)
             continue;
 
-        if (srv->flags.shutdown)
+        if (srv->flags.shutdown || srv->flags.closing)
             continue;
 
         if ((hlp->IsAvailable != NULL) && (srv->data != NULL) && !(hlp->IsAvailable(srv->data)))
@@ -1553,9 +1590,7 @@
             if (srv->flags.shutdown
                     && srv->flags.reserved == S_HELPER_FREE
                     && !srv->deferred_requests) {
-                int wfd = srv->wfd;
-                srv->wfd = -1;
-                comm_close(wfd);
+                helperStatefulDoGracefulClose(srv);
             } else {
                 if (srv->queue.head)
                     helperStatefulServerKickQueue(srv);


