You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@apache.org on 2005/08/28 01:22:56 UTC

svn commit: r241819 - in /httpd/httpd/trunk: docs/manual/mod/mpm_common.xml server/mpm/worker/mpm.h server/mpm/worker/worker.c

Author: colm
Date: Sat Aug 27 16:22:50 2005
New Revision: 241819

URL: http://svn.apache.org/viewcvs?rev=241819&view=rev
Log:

Implement a graceful-stop for the worker MPM. We close our listeners, and then
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.


Modified:
    httpd/httpd/trunk/docs/manual/mod/mpm_common.xml
    httpd/httpd/trunk/server/mpm/worker/mpm.h
    httpd/httpd/trunk/server/mpm/worker/worker.c

Modified: httpd/httpd/trunk/docs/manual/mod/mpm_common.xml
URL: http://svn.apache.org/viewcvs/httpd/httpd/trunk/docs/manual/mod/mpm_common.xml?rev=241819&r1=241818&r2=241819&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mpm_common.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mpm_common.xml Sat Aug 27 16:22:50 2005
@@ -163,7 +163,7 @@
 <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>

Modified: httpd/httpd/trunk/server/mpm/worker/mpm.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/trunk/server/mpm/worker/mpm.h?rev=241819&r1=241818&r2=241819&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/worker/mpm.h (original)
+++ httpd/httpd/trunk/server/mpm/worker/mpm.h Sat Aug 27 16:22:50 2005
@@ -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
 

Modified: httpd/httpd/trunk/server/mpm/worker/worker.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/trunk/server/mpm/worker/worker.c?rev=241819&r1=241818&r2=241819&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/worker/worker.c (original)
+++ httpd/httpd/trunk/server/mpm/worker/worker.c Sat Aug 27 16:22:50 2005
@@ -374,7 +374,7 @@
  * 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 @@
         return;
     }
     shutdown_pending = 1;
+    is_graceful = graceful;
 }
 
 /* do a graceful restart if graceful == 1 */
@@ -401,7 +402,7 @@
 
 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 @@
     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 @@
 #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 @@
     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 */
@@ -1737,6 +1744,63 @@
                          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;
     }
 
     /* we've been told to restart */
@@ -2150,6 +2214,9 @@
   "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 }
 };