the attached patch, based on one bill started, presses SIGINT
into service as a 'graceful shutdown' signal.  (alternative
suggestions highly welcomed.)  if the config directive
GracefulShutdownTimeout is set (default is 10), when the
server is sent a SIGINT it will go into shutdown mode but
not actually go all the way down until that many seconds have
passed.  SIGTERM works normally for a graceless shutdown.

i'd rather not re-add another signal, but oh well.. the
alternative is to set GracefulShutdownTimeout to zero as
the default (either in .c or .conf) to keep the current
behaviour -- but then to take advantage of it you'd need to
edit the .conf file, do a restart, and then do a shutdown.
bleah.

expansion to other mpms and command-line interface waiting
for non-vetoed acceptance of this proof-of-concept.
-- 
#ken    P-)}

Ken Coar, Sanagendamgagwedweinini  http://Golux.Com/coar/
Author, developer, opinionist      http://Apache-Server.Com/

"Millennium hand and shrimp!"
Index: configure.in
===================================================================
RCS file: /home/cvs/httpd-2.0/configure.in,v
retrieving revision 1.246
diff -u -r1.246 configure.in
--- configure.in        8 Mar 2003 13:54:41 -0000       1.246
+++ configure.in        28 Mar 2003 19:30:52 -0000
@@ -164,6 +164,7 @@
 APACHE_SUBST(LTCFLAGS)
 
 AP_SIG_GRACEFUL=USR1
+AP_SIG_GRACEFUL_STOP=INT
 
 case $host in
   *-apple-aux3*)
@@ -477,11 +478,14 @@
 AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL, SIG$AP_SIG_GRACEFUL, [Signal used to gracefully 
restart])
 AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_STRING, "SIG$AP_SIG_GRACEFUL", [Signal used to 
gracefully restart (as a quoted string)])
 AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_SHORT, $AP_SIG_GRACEFUL, [Signal used to 
gracefully restart (without SIG prefix)])
+AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_STOP, SIG$AP_SIG_GRACEFUL_STOP, [Signal used to 
gracefully shut down])
 AP_SIG_GRACEFUL_SHORT=$AP_SIG_GRACEFUL
 AP_SIG_GRACEFUL=SIG$AP_SIG_GRACEFUL_SHORT
+AP_SIG_GRACEFUL_STOP=SIG$AP_SIG_GRACEFUL_STOP
 AC_SUBST(AP_SIG_GRACEFUL)
 AC_SUBST(AP_SIG_GRACEFUL_STRING)
 AC_SUBST(AP_SIG_GRACEFUL_SHORT)
+AC_SUBST(AP_SIG_GRACEFUL_STOP)
 
 dnl check for endianness
 if test "$cross_compiling" = "no"; then
Index: server/mpm/worker/worker.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/worker/worker.c,v
retrieving revision 1.134
diff -u -r1.134 worker.c
--- server/mpm/worker/worker.c  3 Feb 2003 17:53:26 -0000       1.134
+++ server/mpm/worker/worker.c  28 Mar 2003 19:30:52 -0000
@@ -157,6 +157,7 @@
  */
 
 int ap_threads_per_child = 0;         /* Worker threads per child */
+static int graceful_shutdown_timeout = 10;
 static int ap_daemons_to_start = 0;
 static int min_spare_threads = 0;
 static int max_spare_threads = 0;
@@ -436,7 +437,7 @@
  * child to force an exit) and so do an exit anyway.
  */
 
-static void ap_start_shutdown(void)
+static void ap_start_shutdown(int sig)
 {
     if (shutdown_pending == 1) {
         /* Um, is this _probably_ not an error, if the user has
@@ -445,6 +446,13 @@
          */
         return;
     }
+    /*
+     * If it isn't a graceful shutdown, force it to be graceless by
+     * setting the gracefule timeout to zero.
+     */
+    if (sig != AP_SIG_GRACEFUL_STOP) {
+        graceful_shutdown_timeout = 0;
+    }
     shutdown_pending = 1;
 }
 
@@ -462,7 +470,7 @@
 
 static void sig_term(int sig)
 {
-    ap_start_shutdown();
+    ap_start_shutdown(sig);
 }
 
 static void restart(int sig)
@@ -1743,11 +1751,16 @@
     server_main_loop(remaining_children_to_start);
 
     if (shutdown_pending) {
-        /* Time to gracefully shut down:
-         * Kill child processes, tell them to call child_exit, etc...
-         * (By "gracefully" we don't mean graceful in the same sense as 
-         * "apachectl graceful" where we allow old connections to finish.)
+        /* If a graceful_shutdown_timeout is set, allow some time 
+         * for in-flight transactions to complete. If they are not
+         * done by the timeout, take them down hard.
+         * Todo: poll to see if the children have shutdown
+         * to save us from waiting the full timeout period.
          */
+        if (graceful_shutdown_timeout != 0) {
+            ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE);
+            apr_sleep(apr_time_from_sec(graceful_shutdown_timeout));
+        }
         ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
         ap_reclaim_child_processes(1);                /* Start with SIGTERM */
 
@@ -1937,7 +1950,16 @@
     ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
     ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
 }
-
+static const char *set_graceful_shutdown(cmd_parms *cmd, void *dummy,
+                                         const char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+    graceful_shutdown_timeout = atoi(arg);
+    return NULL;
+}
 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
                                         const char *arg) 
 {
@@ -2156,6 +2178,8 @@
 static const command_rec worker_cmds[] = {
 UNIX_DAEMON_COMMANDS,
 LISTEN_COMMANDS,
+AP_INIT_TAKE1("GracefulShutdownTimeout", set_graceful_shutdown, NULL, RSRC_CONF,
+  "Time in seconds to wait for child processes to complete transactions during 
shutdown"),
 AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
   "Number of child processes launched at server startup"),
 AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,

Reply via email to