]> granicus.if.org Git - apache/commitdiff
Implement a graceful-stop for the worker MPM. We close our listeners, and then
authorColm MacCarthaigh <colm@apache.org>
Sat, 27 Aug 2005 23:22:50 +0000 (23:22 +0000)
committerColm MacCarthaigh <colm@apache.org>
Sat, 27 Aug 2005 23:22:50 +0000 (23:22 +0000)
ask each child process to do the same. We then monitor until all children have
exited.

The change to ap_start_shutdown(void) to ap_start_shutdown(int) may look like
an external API change, but the function is defined static, and used only in
one place.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@241819 13f79535-47bb-0310-9956-ffa450edef68

docs/manual/mod/mpm_common.xml
server/mpm/worker/mpm.h
server/mpm/worker/worker.c

index 17daf039c45db357bd3a5a0f70013a8629ff8f8c..e1b2493cedb70a615530acc0131da3ca4ee23d0a 100644 (file)
@@ -163,7 +163,7 @@ will exit.</description>
 <syntax>GracefulShutDownTimeout <var>seconds</var></syntax>
 <default>GracefulShutDownTimeout 0</default>
 <contextlist><context>server config</context></contextlist>
-<modulelist><module>prefork</module></modulelist>
+<modulelist><module>prefork</module><module>worker</module></modulelist>
 <compatibility>Available in version 2.4 and later</compatibility>
 
 <usage>
index 29c9f452fe6940e721b531574b95f8c2d6a0b6a5..509a80afe2877cb53f9d4bfdd6bc2f0f324343a9 100644 (file)
@@ -36,6 +36,7 @@
 #define AP_MPM_WANT_SIGNAL_SERVER
 #define AP_MPM_WANT_SET_MAX_MEM_FREE
 #define AP_MPM_WANT_SET_STACKSIZE
+#define AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
 #define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
 #define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
 
index 904ef4a9028b4bf8fd571a01dd6e0fba3be3d0b0..65d986293cf93b4bc547783d150b7a9af0205227 100644 (file)
@@ -374,7 +374,7 @@ ap_generation_t volatile ap_my_generation;
  * child to force an exit) and so do an exit anyway.
  */
 
-static void ap_start_shutdown(void)
+static void ap_start_shutdown(int graceful)
 {
     mpm_state = AP_MPMQ_STOPPING;
     if (shutdown_pending == 1) {
@@ -385,6 +385,7 @@ static void ap_start_shutdown(void)
         return;
     }
     shutdown_pending = 1;
+    is_graceful = graceful;
 }
 
 /* do a graceful restart if graceful == 1 */
@@ -401,7 +402,7 @@ static void ap_start_restart(int graceful)
 
 static void sig_term(int sig)
 {
-    ap_start_shutdown();
+    ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
 }
 
 static void restart(int sig)
@@ -427,6 +428,11 @@ static void set_signals(void)
     if (sigaction(SIGTERM, &sa, NULL) < 0)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
                      "sigaction(SIGTERM)");
+#ifdef AP_SIG_GRACEFUL_STOP
+    if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
+                     "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
+#endif
 #ifdef SIGINT
     if (sigaction(SIGINT, &sa, NULL) < 0)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
@@ -479,6 +485,9 @@ static void set_signals(void)
 #ifdef AP_SIG_GRACEFUL
     apr_signal(AP_SIG_GRACEFUL, restart);
 #endif /* AP_SIG_GRACEFUL */
+#ifdef AP_SIG_GRACEFUL_STOP
+    apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
+#endif /* AP_SIG_GRACEFUL_STOP */
 #ifdef SIGPIPE
     apr_signal(SIGPIPE, SIG_IGN);
 #endif /* SIGPIPE */
@@ -1714,11 +1723,9 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     server_main_loop(remaining_children_to_start);
     mpm_state = AP_MPMQ_STOPPING;
 
-    if (shutdown_pending) {
-        /* Time to gracefully shut down:
+    if (shutdown_pending && !is_graceful) {
+        /* Time to 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.)
          */
         ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
         ap_reclaim_child_processes(1);                /* Start with SIGTERM */
@@ -1736,6 +1743,63 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
             ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
                          ap_server_conf, "caught SIGTERM, shutting down");
         }
+        return 1;
+    } else if (shutdown_pending) {
+        /* Time to gracefully shut down:
+         * Kill child processes, tell them to call child_exit, etc...
+         */
+        int active_children;
+        int index;
+        apr_time_t cutoff = 0;
+
+        /* Close our listeners, and then ask our children to do same */
+        ap_close_listeners();
+        ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE);
+        ap_relieve_child_processes();
+
+        if (!child_fatal) {
+            /* cleanup pid file on normal shutdown */
+            const char *pidfile = NULL;
+            pidfile = ap_server_root_relative (pconf, ap_pid_fname);
+            if ( pidfile != NULL && unlink(pidfile) == 0)
+                ap_log_error(APLOG_MARK, APLOG_INFO, 0,
+                             ap_server_conf,
+                             "removed PID file %s (pid=%ld)",
+                             pidfile, (long)getpid());
+    
+            ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
+                         ap_server_conf, "caught SIGTERM, shutting down");
+        }
+
+        /* Don't really exit until each child has finished */
+        shutdown_pending = 0;
+        do {
+            /* Pause for a second */
+            apr_sleep(apr_time_from_sec(1));
+                
+            /* Relieve any children which have now exited */
+            ap_relieve_child_processes();
+            
+            active_children = 0;
+            for (index = 0; index < ap_daemons_limit; ++index) {
+                if (MPM_CHILD_PID(index) != 0) {
+                    if (kill(MPM_CHILD_PID(index), 0) == 0) {
+                            active_children = 1;
+                            /* Having just one child is enough to stay around */
+                            break;
+                    }
+                }
+            }
+        } while (!shutdown_pending && active_children &&
+                 (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
+
+        /* We might be here because we received SIGTERM, either
+         * way, try and make sure that all of our processes are
+         * really dead.
+         */
+        ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
+        ap_reclaim_child_processes(1);
+
         return 1;
     }
 
@@ -2150,6 +2214,9 @@ AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
   "Maximum number of child processes for this run of Apache"),
 AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
   "Maximum number of worker threads per child process for this run of Apache - Upper limit for ThreadsPerChild"),
+AP_INIT_TAKE1("GracefulShutdownTimeout", ap_mpm_set_graceful_shutdown, NULL, 
+              RSRC_CONF, "Time in seconds to wait for child processes to " 
+              "complete transactions during shutdown"),
 { NULL }
 };