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/09/19 17:51:34 UTC
svn commit: r290189 - in /httpd/httpd: branches/2.2.x/
branches/2.2.x/include/ branches/2.2.x/server/
branches/2.2.x/server/mpm/experimental/event/
branches/2.2.x/server/mpm/prefork/ branches/2.2.x/server/mpm/worker/
branches/2.2.x/support/ trunk/
Author: colm
Date: Mon Sep 19 08:51:22 2005
New Revision: 290189
URL: http://svn.apache.org/viewcvs?rev=290189&view=rev
Log:
Backport graceful-stop to the 2.2.x branch.
Modified:
httpd/httpd/branches/2.2.x/CHANGES
httpd/httpd/branches/2.2.x/include/mpm_common.h
httpd/httpd/branches/2.2.x/server/main.c
httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c
httpd/httpd/branches/2.2.x/server/mpm/experimental/event/mpm.h
httpd/httpd/branches/2.2.x/server/mpm/prefork/mpm.h
httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c
httpd/httpd/branches/2.2.x/server/mpm/worker/mpm.h
httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c
httpd/httpd/branches/2.2.x/server/mpm_common.c
httpd/httpd/branches/2.2.x/support/apachectl.in
httpd/httpd/trunk/CHANGES
Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/CHANGES?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Mon Sep 19 08:51:22 2005
@@ -1,6 +1,11 @@
-*- coding: utf-8 -*-
Changes with Apache 2.1.8
+ *) prefork, worker and event MPMs: Support a graceful-stop procedure:
+ Server will wait until existing requests are finished or until
+ "GracefulShutdownTimeout" number of seconds before exiting.
+ [Colm MacCarthaigh, Ken Coar, Bill Stoddard]
+
*) prefork, worker and event MPMs: Prevent children from holding open
listening ports upon graceful restart or stop. PR 28167.
[Colm MacCarthaigh, Brian Pinkerton <bp thinkpink.com>]
Modified: httpd/httpd/branches/2.2.x/include/mpm_common.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/include/mpm_common.h?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/include/mpm_common.h (original)
+++ httpd/httpd/branches/2.2.x/include/mpm_common.h Mon Sep 19 08:51:22 2005
@@ -65,6 +65,15 @@
/* Signal used to gracefully restart (as a quoted string) */
#define AP_SIG_GRACEFUL_STRING "SIGUSR1"
+/* Signal used to gracefully stop */
+#define AP_SIG_GRACEFUL_STOP SIGWINCH
+
+/* Signal used to gracefully stop (without SIG prefix) */
+#define AP_SIG_GRACEFUL_STOP_SHORT WINCH
+
+/* Signal used to gracefully stop (as a quoted string) */
+#define AP_SIG_GRACEFUL_STOP_STRING "SIGWINCH"
+
/**
* Make sure all child processes that have been spawned by the parent process
* have died. This includes process registered as "other_children".
@@ -86,8 +95,25 @@
#endif
/**
- * Tell ap_reclaim_child_processes() about an MPM child process which has no
- * entry in the scoreboard.
+ * Catch any child processes that have been spawned by the parent process
+ * which have exited. This includes processes registered as "other_children".
+ * @warning This is only defined if the MPM defines
+ * AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
+ * @tip This function requires that some macros are defined by the MPM: <pre>
+ * MPM_CHILD_PID -- Get the pid from the specified spot in the scoreboard
+ * MPM_NOTE_CHILD_KILLED -- Note the child died in the scoreboard
+ * </pre>
+ * @tip The MPM child processes which are relieved are those listed
+ * in the scoreboard as well as those currently registered via
+ * ap_register_extra_mpm_process().
+ */
+#ifdef AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
+void ap_relieve_child_processes(void);
+#endif
+
+/**
+ * Tell ap_reclaim_child_processes() and ap_relieve_child_processes() about
+ * an MPM child process which has no entry in the scoreboard.
* @warning This is only defined if the MPM defines
* AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
* @param pid The process id of an MPM child process which should be
@@ -277,6 +303,20 @@
const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
const char *arg);
#endif
+
+/**
+ * Set the timeout period for a graceful shutdown.
+ */
+#ifdef AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
+extern int ap_graceful_shutdown_timeout;
+const char *ap_mpm_set_graceful_shutdown(cmd_parms *cmd, void *dummy,
+ const char *arg);
+#define AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND \
+AP_INIT_TAKE1("GracefulShutdownTimeout", ap_mpm_set_graceful_shutdown, NULL, \
+ RSRC_CONF, "Maximum time in seconds to wait for child " \
+ "processes to complete transactions during shutdown")
+#endif
+
#ifdef AP_MPM_WANT_SIGNAL_SERVER
int ap_signal_server(int *, apr_pool_t *);
Modified: httpd/httpd/branches/2.2.x/server/main.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/main.c?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/main.c (original)
+++ httpd/httpd/branches/2.2.x/server/main.c Mon Sep 19 08:51:22 2005
@@ -318,9 +318,15 @@
pad);
#endif
#ifdef AP_MPM_WANT_SIGNAL_SERVER
+#ifdef AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ " %s [-k start|restart|graceful|graceful-stop|stop]",
+ pad);
+#else
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" %s [-k start|restart|graceful|stop]",
pad);
+#endif /* AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN */
#endif
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" %s [-v] [-V] [-h] [-l] [-L] [-t] [-S]", pad);
Modified: httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c Mon Sep 19 08:51:22 2005
@@ -416,7 +416,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) {
@@ -427,6 +427,7 @@
return;
}
shutdown_pending = 1;
+ is_graceful = graceful;
}
/* do a graceful restart if graceful == 1 */
@@ -443,7 +444,7 @@
static void sig_term(int sig)
{
- ap_start_shutdown();
+ ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
}
static void restart(int sig)
@@ -469,6 +470,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,
@@ -521,6 +527,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 */
@@ -598,9 +607,8 @@
* accept() with a socket readability check, like Win32,
* and there are measurable delays before the
* socket is readable due to the first data packet arriving,
- * it might be better to create the cs on the listener thread,
- * set the state to CONN_STATE_CHECK_REQUEST_LINE_READABLE,
- * and give it to the event thread.
+ * it might be better to create the cs on the listener thread
+ * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE
*
* FreeBSD users will want to enable the HTTP accept filter
* module in their kernel for the highest performance
@@ -1925,11 +1933,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 */
@@ -1948,7 +1954,64 @@
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 */
apr_signal(SIGHUP, SIG_IGN);
@@ -2371,6 +2434,7 @@
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_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
{NULL}
};
Modified: httpd/httpd/branches/2.2.x/server/mpm/experimental/event/mpm.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm/experimental/event/mpm.h?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/experimental/event/mpm.h (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/experimental/event/mpm.h Mon Sep 19 08:51:22 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/branches/2.2.x/server/mpm/prefork/mpm.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm/prefork/mpm.h?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/prefork/mpm.h (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/prefork/mpm.h Mon Sep 19 08:51:22 2005
@@ -38,6 +38,7 @@
#define AP_MPM_WANT_SIGNAL_SERVER
#define AP_MPM_WANT_SET_MAX_MEM_FREE
#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
+#define AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
#define AP_MPM_USES_POD 1
Modified: httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c Mon Sep 19 08:51:22 2005
@@ -138,7 +138,7 @@
char tpf_server_name[INETD_SERVNAME_LENGTH+1];
#endif /* TPF */
-static int die_now = 0;
+static volatile int die_now = 0;
#ifdef GPROF
/*
@@ -331,6 +331,9 @@
static void stop_listening(int sig)
{
ap_close_listeners();
+
+ /* For a graceful stop, we want the child to exit when done */
+ die_now = 1;
}
/* volatile just in case */
@@ -348,6 +351,7 @@
return;
}
shutdown_pending = 1;
+ is_graceful = (sig == AP_SIG_GRACEFUL_STOP);
}
/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL
@@ -380,6 +384,11 @@
sa.sa_handler = sig_term;
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, "sigaction(SIGINT)");
@@ -427,6 +436,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 */
#ifdef SIGPIPE
apr_signal(SIGPIPE, SIG_IGN);
#endif /* SIGPIPE */
@@ -1071,8 +1083,8 @@
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...
*/
if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
@@ -1094,6 +1106,82 @@
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
"caught SIGTERM, shutting down");
return 1;
+ } else if (shutdown_pending) {
+ /* Time to perform a graceful shut down:
+ * Reap the inactive children, and ask the active ones
+ * to close their listeners, then wait until they are
+ * all done to exit.
+ */
+ int active_children;
+ apr_time_t cutoff = 0;
+
+ /* Stop listening */
+ ap_close_listeners();
+
+ /* kill off the idle ones */
+ ap_mpm_pod_killpg(pod, ap_max_daemons_limit);
+
+ /* Send SIGUSR1 to the active children */
+ active_children = 0;
+ for (index = 0; index < ap_daemons_limit; ++index) {
+ if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
+ /* Ask each child to close its listeners. */
+ kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL);
+ active_children++;
+ }
+ }
+
+ /* Allow each child which actually finished to exit */
+ ap_relieve_child_processes();
+
+ /* cleanup pid file */
+ {
+ 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 " AP_SIG_GRACEFUL_STOP_STRING ", shutting down gracefully");
+
+ if (ap_graceful_shutdown_timeout) {
+ cutoff = apr_time_now() +
+ apr_time_from_sec(ap_graceful_shutdown_timeout);
+ }
+
+ /* Don't really exit until each child has finished */
+ shutdown_pending = 0;
+ do {
+ /* Pause for a second */
+ sleep(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.
+ */
+ unixd_killpg(getpgrp(), SIGTERM);
+
+ return 1;
}
/* we've been told to restart */
@@ -1373,6 +1461,7 @@
"Maximum number of children alive at the same time"),
AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
"Maximum value of MaxClients for this run of Apache"),
+AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
{ NULL }
};
Modified: httpd/httpd/branches/2.2.x/server/mpm/worker/mpm.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm/worker/mpm.h?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/worker/mpm.h (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/worker/mpm.h Mon Sep 19 08:51:22 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/branches/2.2.x/server/mpm/worker/worker.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c Mon Sep 19 08:51:22 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 */
@@ -1730,12 +1737,69 @@
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());
+ "removed PID file %s (pid=%" APR_PID_T_FMT ")",
+ pidfile, getpid());
+
+ 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=%" APR_PID_T_FMT ")",
+ pidfile, 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,7 @@
"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_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
{ NULL }
};
Modified: httpd/httpd/branches/2.2.x/server/mpm_common.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/server/mpm_common.c?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm_common.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm_common.c Mon Sep 19 08:51:22 2005
@@ -273,6 +273,38 @@
} while (not_dead_yet > 0 &&
action_table[cur_action].action != GIVEUP);
}
+
+void ap_relieve_child_processes(void)
+{
+ int i;
+ extra_process_t *cur_extra;
+ int max_daemons;
+
+ ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);
+
+ /* now see who is done */
+ for (i = 0; i < max_daemons; ++i) {
+ pid_t pid = MPM_CHILD_PID(i);
+
+ if (pid == 0) {
+ continue; /* not every scoreboard entry is in use */
+ }
+
+ if (reclaim_one_pid(pid, DO_NOTHING)) {
+ MPM_NOTE_CHILD_KILLED(i);
+ }
+ }
+
+ cur_extra = extras;
+ while (cur_extra) {
+ extra_process_t *next = cur_extra->next;
+
+ if (reclaim_one_pid(cur_extra->pid, DO_NOTHING)) {
+ AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid));
+ }
+ cur_extra = next;
+ }
+}
#endif /* AP_MPM_WANT_RECLAIM_CHILD_PROCESSES */
#ifdef AP_MPM_WANT_WAIT_OR_TIMEOUT
@@ -760,6 +792,21 @@
}
#endif
+#ifdef AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
+int ap_graceful_shutdown_timeout = 0;
+
+const char * ap_mpm_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;
+ }
+ ap_graceful_shutdown_timeout = atoi(arg);
+ return NULL;
+}
+#endif
+
#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
apr_lockmech_e ap_accept_lock_mech = APR_LOCK_DEFAULT;
@@ -921,6 +968,20 @@
return 1;
}
}
+
+ if (!strcmp(dash_k_arg, "graceful-stop")) {
+#ifdef AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
+ if (!running) {
+ printf("%s\n", status);
+ }
+ else {
+ *exit_status = send_signal(otherpid, AP_SIG_GRACEFUL_STOP);
+ }
+#else
+ printf("httpd MPM \"" MPM_NAME "\" does not support graceful-stop\n");
+#endif
+ return 1;
+ }
return 0;
}
@@ -949,7 +1010,8 @@
case 'k':
if (!dash_k_arg) {
if (!strcmp(optarg, "start") || !strcmp(optarg, "stop") ||
- !strcmp(optarg, "restart") || !strcmp(optarg, "graceful")) {
+ !strcmp(optarg, "restart") || !strcmp(optarg, "graceful") ||
+ !strcmp(optarg, "graceful-stop")) {
dash_k_arg = optarg;
break;
}
Modified: httpd/httpd/branches/2.2.x/support/apachectl.in
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.2.x/support/apachectl.in?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/support/apachectl.in (original)
+++ httpd/httpd/branches/2.2.x/support/apachectl.in Mon Sep 19 08:51:22 2005
@@ -76,7 +76,7 @@
fi
case $ARGV in
-start|stop|restart|graceful)
+start|stop|restart|graceful|graceful-stop)
$HTTPD -k $ARGV
ERROR=$?
;;
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewcvs/httpd/httpd/trunk/CHANGES?rev=290189&r1=290188&r2=290189&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Mon Sep 19 08:51:22 2005
@@ -23,17 +23,17 @@
*) Doxygen fixup [Neale Ranns <neale ranns.org>, Ian Holsman]
- *) prefork, worker and event MPMs: Support a graceful-stop procedure:
- Server will wait until existing requests are finished or until
- "GracefulShutdownTimeout" number of seconds before exiting.
- [Colm MacCarthaigh, Ken Coar, Bill Stoddard]
-
*) Teach mod_ssl to use arbitrary OIDs in an SSLRequire directive,
allowing string-valued client certificate attributes to be used for
access control, as in: SSLRequire "value" in OID("1.3.6.1.4.1.18060.1")
[Martin Kraemer, David Reid]
Changes with Apache 2.1.8
+
+ *) prefork, worker and event MPMs: Support a graceful-stop procedure:
+ Server will wait until existing requests are finished or until
+ "GracefulShutdownTimeout" number of seconds before exiting.
+ [Colm MacCarthaigh, Ken Coar, Bill Stoddard]
*) prefork, worker and event MPMs: Prevent children from holding open
listening ports upon graceful restart or stop. PR 28167.