]> granicus.if.org Git - apache/commitdiff
Merge r1783849 from trunk:
authorYann Ylavic <ylavic@apache.org>
Fri, 2 Jun 2017 10:58:38 +0000 (10:58 +0000)
committerYann Ylavic <ylavic@apache.org>
Fri, 2 Jun 2017 10:58:38 +0000 (10:58 +0000)
MPMs unix: Place signals handlers and helpers out of DSOs to avoid
a possible crash if a signal is caught during (graceful) restart.
PR 60487.

Reviewedby: ylavic, wrowe, icing

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1797368 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
os/unix/unixd.c
os/unix/unixd.h
server/mpm/event/event.c
server/mpm/prefork/prefork.c
server/mpm/worker/worker.c
server/mpm_unix.c

diff --git a/CHANGES b/CHANGES
index 9d7fe8e379bb314fffb1aba45006d1da461c9683..a817ae0f209aaea6bafc6038fae9545445d024b2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@
 
 Changes with Apache 2.4.26
 
+  *) MPMs unix: Place signals handlers and helpers out of DSOs to avoid
+     a possible crash if a signal is caught during (graceful) restart.
+     PR 60487.  [Yann Ylavic]
+
   *) core: Deprecate ap_get_basic_auth_pw() and add
      ap_get_basic_auth_components().
      [Emmanuel Dreyfus <manu netbsd.org>, Jacob Champion, Eric Covener]
diff --git a/STATUS b/STATUS
index 856fce5b26ca475ba208aff4e4e154c6621902e4..6783fb89593f606f552e16c94fa04292f65df56a 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -120,13 +120,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  *) MPMs unix: Place signals handlers and helpers out of DSOs to avoid a
-     possible crash if a signal is caught during (graceful) restart. PR 60487.
-     trunk patch: http://svn.apache.org/r1783849
-     2.4.x patch: svn merge -c 1783849 ^/httpd/httpd/trunk .
-                  (trunk works, modulo CHANGES)
-     +1: ylavic, wrowe, icing
-
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]
 
index d7042bf6867012853d952a334c7efe0d91f3bb6c..07a9bef754c5102e655aec37eb48d613fe637105 100644 (file)
@@ -434,6 +434,155 @@ AP_DECLARE(apr_status_t) ap_unixd_accept(void **accepted, ap_listen_rec *lr,
 }
 
 
+/* Unixes MPMs' */
+
+static ap_unixd_mpm_retained_data *retained_data = NULL;
+AP_DECLARE(ap_unixd_mpm_retained_data *) ap_unixd_mpm_get_retained_data()
+{
+    if (!retained_data) {
+        retained_data = ap_retained_data_create("ap_unixd_mpm_retained_data",
+                                                sizeof(*retained_data));
+        retained_data->mpm_state = AP_MPMQ_STARTING;
+    }
+    return retained_data;
+}
+
+static void sig_term(int sig)
+{
+    retained_data->mpm_state = AP_MPMQ_STOPPING;
+    if (retained_data->shutdown_pending
+            && (retained_data->is_ungraceful
+                || sig == AP_SIG_GRACEFUL_STOP)) {
+        /* Already handled */
+        return;
+    }
+
+    retained_data->shutdown_pending = 1;
+    if (sig != AP_SIG_GRACEFUL_STOP) {
+        retained_data->is_ungraceful = 1;
+    }
+}
+
+static void sig_restart(int sig)
+{
+    retained_data->mpm_state = AP_MPMQ_STOPPING;
+    if (retained_data->restart_pending
+            && (retained_data->is_ungraceful
+                || sig == AP_SIG_GRACEFUL)) {
+        /* Already handled */
+        return;
+    }
+
+    retained_data->restart_pending = 1;
+    if (sig != AP_SIG_GRACEFUL) {
+        retained_data->is_ungraceful = 1;
+    }
+}
+
+static apr_status_t unset_signals(void *unused)
+{
+    retained_data->shutdown_pending = retained_data->restart_pending = 0;
+    retained_data->was_graceful = !retained_data->is_ungraceful;
+    retained_data->is_ungraceful = 0;
+
+    return APR_SUCCESS;
+}
+
+AP_DECLARE(void) ap_unixd_mpm_set_signals(apr_pool_t *pconf, int one_process)
+{
+#ifndef NO_USE_SIGACTION
+    struct sigaction sa;
+#endif
+
+    /* Signals' handlers depend on retained data */
+    (void)ap_unixd_mpm_get_retained_data();
+
+#ifndef NO_USE_SIGACTION
+    memset(&sa, 0, sizeof sa);
+    sigemptyset(&sa.sa_mask);
+
+#ifdef SIGPIPE
+    sa.sa_handler = SIG_IGN;
+    if (sigaction(SIGPIPE, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00269)
+                     "sigaction(SIGPIPE)");
+#endif
+#ifdef SIGXCPU
+    sa.sa_handler = SIG_DFL;
+    if (sigaction(SIGXCPU, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00267)
+                     "sigaction(SIGXCPU)");
+#endif
+#ifdef SIGXFSZ
+    /* For systems following the LFS standard, ignoring SIGXFSZ allows
+     * a write() beyond the 2GB limit to fail gracefully with E2BIG
+     * rather than terminate the process. */
+    sa.sa_handler = SIG_IGN;
+    if (sigaction(SIGXFSZ, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00268)
+                     "sigaction(SIGXFSZ)");
+#endif
+
+    sa.sa_handler = sig_term;
+    if (sigaction(SIGTERM, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00264)
+                     "sigaction(SIGTERM)");
+#ifdef SIGINT
+    if (sigaction(SIGINT, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00266)
+                     "sigaction(SIGINT)");
+#endif
+#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, APLOGNO(00265)
+                     "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
+#endif
+
+    /* Don't catch restart signals in ONE_PROCESS mode :) */
+    if (!one_process) {
+        sa.sa_handler = sig_restart;
+        if (sigaction(SIGHUP, &sa, NULL) < 0)
+            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00270)
+                         "sigaction(SIGHUP)");
+        if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
+            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00271)
+                         "sigaction(" AP_SIG_GRACEFUL_STRING ")");
+    }
+
+#else  /* NO_USE_SIGACTION */
+
+#ifdef SIGPIPE
+    apr_signal(SIGPIPE, SIG_IGN);
+#endif /* SIGPIPE */
+#ifdef SIGXCPU
+    apr_signal(SIGXCPU, SIG_DFL);
+#endif /* SIGXCPU */
+#ifdef SIGXFSZ
+    apr_signal(SIGXFSZ, SIG_IGN);
+#endif /* SIGXFSZ */
+
+    apr_signal(SIGTERM, sig_term);
+#ifdef AP_SIG_GRACEFUL_STOP
+    apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
+#endif /* AP_SIG_GRACEFUL_STOP */
+
+    if (!one_process) {
+        /* Don't restart in ONE_PROCESS mode :) */
+#ifdef SIGHUP
+        apr_signal(SIGHUP, sig_restart);
+#endif /* SIGHUP */
+#ifdef AP_SIG_GRACEFUL
+        apr_signal(AP_SIG_GRACEFUL, sig_restart);
+#endif /* AP_SIG_GRACEFUL */
+    }
+
+#endif /* NO_USE_SIGACTION */
+
+    apr_pool_cleanup_register(pconf, NULL, unset_signals,
+                              apr_pool_cleanup_null);
+}
+
+
 #ifdef _OSD_POSIX
 
 #include "apr_lib.h"
index 74961c348e68856318c4aa1ca41d1aa7f6c50de5..ed977c6fde5f94e082bd1d2c9dd27c2d3275b4c3 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "httpd.h"
 #include "http_config.h"
+#include "scoreboard.h"
 #include "ap_listen.h"
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -109,6 +110,30 @@ AP_DECLARE(apr_status_t) ap_unixd_accept(void **accepted, ap_listen_rec *lr, apr
 #define ap_os_killpg(x, y)      (kill (-(x), (y)))
 #endif /* HAVE_KILLPG */
 
+typedef struct {
+    void            *baton;  /* MPM's */
+
+    /* volatile because they're updated from signals' handlers */
+    int volatile    mpm_state;
+    int volatile    shutdown_pending;
+    int volatile    restart_pending;
+    int volatile    is_ungraceful;
+
+    ap_generation_t my_generation;
+    int             module_loads;
+    int             was_graceful;
+
+    /*
+     * Current number of listeners buckets and maximum reached across
+     * restarts (to size retained data according to dynamic num_buckets,
+     * eg. idle_spawn_rate).
+     */
+    int num_buckets, max_buckets;
+} ap_unixd_mpm_retained_data;
+
+AP_DECLARE(ap_unixd_mpm_retained_data *) ap_unixd_mpm_get_retained_data(void);
+AP_DECLARE(void) ap_unixd_mpm_set_signals(apr_pool_t *pconf, int once_process);
+
 #ifdef __cplusplus
 }
 #endif
index 0ae597ebfe2d37657d1cc8d2678c446d811192f6..6bbc8e55725ff22409ee1efdf4f997a8a8d78fdb 100644 (file)
@@ -189,7 +189,6 @@ static apr_uint32_t threads_shutdown = 0;   /* Number of threads that have shutd
 static int resource_shortage = 0;
 static fd_queue_t *worker_queue;
 static fd_queue_info_t *worker_queue_info;
-static int mpm_state = AP_MPMQ_STARTING;
 
 static apr_thread_mutex_t *timeout_mutex;
 
@@ -325,12 +324,11 @@ typedef struct
  * subsequent calls to pre-config hook
  */
 typedef struct event_retained_data {
+    ap_unixd_mpm_retained_data *mpm;
+
     int first_server_limit;
     int first_thread_limit;
-    int module_loads;
     int sick_child_detected;
-    ap_generation_t my_generation;
-    int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     /*
      * The max child slot ever assigned, preserved across restarts.  Necessary
@@ -358,12 +356,6 @@ typedef struct event_retained_data {
 #define MAX_SPAWN_RATE        (32)
 #endif
     int hold_off_on_exponential_spawning;
-    /*
-     * Current number of listeners buckets and maximum reached across
-     * restarts (to size retained data according to dynamic num_buckets,
-     * eg. idle_spawn_rate).
-     */
-    int num_buckets, max_buckets;
 } event_retained_data;
 static event_retained_data *retained;
  
@@ -504,7 +496,7 @@ static void signal_threads(int mode)
         return;
     }
     terminate_mode = mode;
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
 
     /* in case we weren't called from the listener thread, wake up the
      * listener thread
@@ -566,10 +558,10 @@ static int event_query(int query_code, int *result, apr_status_t *rv)
         *result = active_daemons_limit;
         break;
     case AP_MPMQ_MPM_STATE:
-        *result = mpm_state;
+        *result = retained->mpm->mpm_state;
         break;
     case AP_MPMQ_GENERATION:
-        *result = retained->my_generation;
+        *result = retained->mpm->my_generation;
         break;
     default:
         *rv = APR_ENOTIMPL;
@@ -597,7 +589,7 @@ static void event_note_child_started(int slot, pid_t pid)
     ap_scoreboard_image->parent[slot].pid = pid;
     ap_run_child_status(ap_server_conf,
                         ap_scoreboard_image->parent[slot].pid,
-                        retained->my_generation, slot, MPM_CHILD_STARTED);
+                        retained->mpm->my_generation, slot, MPM_CHILD_STARTED);
 }
 
 static const char *event_get_name(void)
@@ -609,7 +601,7 @@ static const char *event_get_name(void)
 static void clean_child_exit(int code) __attribute__ ((noreturn));
 static void clean_child_exit(int code)
 {
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
     if (pchild) {
         apr_pool_destroy(pchild);
     }
@@ -632,10 +624,6 @@ static void just_die(int sig)
 
 static int child_fatal;
 
-/* volatile because they're updated from a signal handler */
-static int volatile shutdown_pending;
-static int volatile restart_pending;
-
 static apr_status_t decrement_connection_count(void *cs_)
 {
     event_conn_state_t *cs = cs_;
@@ -654,149 +642,6 @@ static apr_status_t decrement_connection_count(void *cs_)
     return APR_SUCCESS;
 }
 
-/*
- * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
- * functions to initiate shutdown or restart without relying on signals.
- * Previously this was initiated in sig_term() and restart() signal handlers,
- * but we want to be able to start a shutdown/restart from other sources --
- * e.g. on Win32, from the service manager. Now the service manager can
- * call ap_start_shutdown() or ap_start_restart() as appropriate.  Note that
- * these functions can also be called by the child processes, since global
- * variables are no longer used to pass on the required action to the parent.
- *
- * These should only be called from the parent process itself, since the
- * parent process will use the shutdown_pending and restart_pending variables
- * to determine whether to shutdown or restart. The child process should
- * call signal_parent() directly to tell the parent to die -- this will
- * cause neither of those variable to be set, which the parent will
- * assume means something serious is wrong (which it will be, for the
- * child to force an exit) and so do an exit anyway.
- */
-
-static void ap_start_shutdown(int graceful)
-{
-    mpm_state = AP_MPMQ_STOPPING;
-    if (shutdown_pending == 1) {
-        /* Um, is this _probably_ not an error, if the user has
-         * tried to do a shutdown twice quickly, so we won't
-         * worry about reporting it.
-         */
-        return;
-    }
-    shutdown_pending = 1;
-    retained->is_graceful = graceful;
-}
-
-/* do a graceful restart if graceful == 1 */
-static void ap_start_restart(int graceful)
-{
-    mpm_state = AP_MPMQ_STOPPING;
-    if (restart_pending == 1) {
-        /* Probably not an error - don't bother reporting it */
-        return;
-    }
-    restart_pending = 1;
-    retained->is_graceful = graceful;
-}
-
-static void sig_term(int sig)
-{
-    ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
-}
-
-static void restart(int sig)
-{
-    ap_start_restart(sig == AP_SIG_GRACEFUL);
-}
-
-static void set_signals(void)
-{
-#ifndef NO_USE_SIGACTION
-    struct sigaction sa;
-#endif
-
-    if (!one_process) {
-        ap_fatal_signal_setup(ap_server_conf, pconf);
-    }
-
-#ifndef NO_USE_SIGACTION
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-
-    sa.sa_handler = sig_term;
-    if (sigaction(SIGTERM, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00459)
-                     "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, APLOGNO(00460)
-                     "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, APLOGNO(00461)
-                     "sigaction(SIGINT)");
-#endif
-#ifdef SIGXCPU
-    sa.sa_handler = SIG_DFL;
-    if (sigaction(SIGXCPU, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00462)
-                     "sigaction(SIGXCPU)");
-#endif
-#ifdef SIGXFSZ
-    /* For systems following the LFS standard, ignoring SIGXFSZ allows
-     * a write() beyond the 2GB limit to fail gracefully with E2BIG
-     * rather than terminate the process. */
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGXFSZ, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00463)
-                     "sigaction(SIGXFSZ)");
-#endif
-#ifdef SIGPIPE
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGPIPE, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00464)
-                     "sigaction(SIGPIPE)");
-#endif
-
-    /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
-     * processing one */
-    sigaddset(&sa.sa_mask, SIGHUP);
-    sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
-    sa.sa_handler = restart;
-    if (sigaction(SIGHUP, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00465)
-                     "sigaction(SIGHUP)");
-    if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00466)
-                     "sigaction(" AP_SIG_GRACEFUL_STRING ")");
-#else
-    if (!one_process) {
-#ifdef SIGXCPU
-        apr_signal(SIGXCPU, SIG_DFL);
-#endif /* SIGXCPU */
-#ifdef SIGXFSZ
-        apr_signal(SIGXFSZ, SIG_IGN);
-#endif /* SIGXFSZ */
-    }
-
-    apr_signal(SIGTERM, sig_term);
-#ifdef SIGHUP
-    apr_signal(SIGHUP, restart);
-#endif /* SIGHUP */
-#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 */
-
-#endif
-}
-
 static void notify_suspend(event_conn_state_t *cs)
 {
     ap_run_suspend_connection(cs->c, cs->r);
@@ -1930,7 +1775,7 @@ static void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy)
 
     ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
     ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current();
-    ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation;
+    ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->mpm->my_generation;
     ap_update_child_status_from_indexes(process_slot, thread_slot,
                                         SERVER_STARTING, NULL);
 
@@ -2280,15 +2125,15 @@ static void child_main(int child_num_arg, int child_bucket)
     apr_thread_t *start_thread_id;
     int i;
 
-    mpm_state = AP_MPMQ_STARTING;       /* for benefit of any hooks that run as this
-                                         * child initializes
-                                         */
+    /* for benefit of any hooks that run as this child initializes */
+    retained->mpm->mpm_state = AP_MPMQ_STARTING;
+
     ap_my_pid = getpid();
     ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
     /* close unused listeners and pods */
-    for (i = 0; i < retained->num_buckets; i++) {
+    for (i = 0; i < retained->mpm->num_buckets; i++) {
         if (i != child_bucket) {
             ap_close_listeners_ex(all_buckets[i].listeners);
             ap_mpm_podx_close(all_buckets[i].pod);
@@ -2365,7 +2210,7 @@ static void child_main(int child_num_arg, int child_bucket)
         clean_child_exit(APEXIT_CHILDSICK);
     }
 
-    mpm_state = AP_MPMQ_RUNNING;
+    retained->mpm->mpm_state = AP_MPMQ_RUNNING;
 
     /* If we are only running in one_process mode, we will want to
      * still handle signals. */
@@ -2462,7 +2307,6 @@ static int make_child(server_rec * s, int slot, int bucket)
     if (one_process) {
         my_bucket = &all_buckets[0];
 
-        set_signals();
         event_note_child_started(slot, getpid());
         child_main(slot, 0);
         /* NOTREACHED */
@@ -2530,7 +2374,7 @@ static void startup_children(int number_to_start)
         if (ap_scoreboard_image->parent[i].pid != 0) {
             continue;
         }
-        if (make_child(ap_server_conf, i, i % retained->num_buckets) < 0) {
+        if (make_child(ap_server_conf, i, i % retained->mpm->num_buckets) < 0) {
             break;
         }
         --number_to_start;
@@ -2575,7 +2419,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
                  * This depends on the ordering of SERVER_READY and SERVER_STARTING.
                  */
                 if (status <= SERVER_READY && !ps->quiescing && !ps->not_accepting
-                    && ps->generation == retained->my_generation
+                    && ps->generation == retained->mpm->my_generation
                     && ps->bucket == child_bucket)
                 {
                     ++idle_thread_count;
@@ -2604,7 +2448,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
         else {
             /* looks like a basket case, as no child ever fully initialized; give up.
              */
-            shutdown_pending = 1;
+            retained->mpm->shutdown_pending = 1;
             child_fatal = 1;
             ap_log_error(APLOG_MARK, APLOG_ALERT, 0,
                          ap_server_conf, APLOGNO(02324)
@@ -2716,7 +2560,7 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
     apr_proc_t pid;
     int i;
 
-    while (!restart_pending && !shutdown_pending) {
+    while (!retained->mpm->restart_pending && !retained->mpm->shutdown_pending) {
         ap_wait_or_timeout(&exitwhy, &status, &pid, pconf, ap_server_conf);
 
         if (pid.pid != -1) {
@@ -2730,8 +2574,8 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
                  */
                 if (child_slot < 0
                     || ap_get_scoreboard_process(child_slot)->generation
-                       == retained->my_generation) {
-                    shutdown_pending = 1;
+                       == retained->mpm->my_generation) {
+                    retained->mpm->shutdown_pending = 1;
                     child_fatal = 1;
                     /*
                      * total_daemons counting will be off now, but as we
@@ -2786,7 +2630,7 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
                 /* handled */
             }
 #endif
-            else if (retained->is_graceful) {
+            else if (retained->mpm->was_graceful) {
                 /* Great, we've probably just lost a slot in the
                  * scoreboard.  Somehow we don't know about this child.
                  */
@@ -2824,25 +2668,27 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
 
 static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
 {
-    int num_buckets = retained->num_buckets;
+    int num_buckets = retained->mpm->num_buckets;
     int remaining_children_to_start;
     int i;
 
     ap_log_pid(pconf, ap_pid_fname);
 
-    if (!retained->is_graceful) {
+    if (!retained->mpm->was_graceful) {
         if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
-            mpm_state = AP_MPMQ_STOPPING;
+            retained->mpm->mpm_state = AP_MPMQ_STOPPING;
             return !OK;
         }
         /* fix the generation number in the global score; we just got a new,
          * cleared scoreboard
          */
-        ap_scoreboard_image->global->running_generation = retained->my_generation;
+        ap_scoreboard_image->global->running_generation = retained->mpm->my_generation;
     }
 
-    restart_pending = shutdown_pending = 0;
-    set_signals();
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
+    ap_unixd_mpm_set_signals(pconf, one_process);
 
     /* Don't thrash since num_buckets depends on the
      * system and the number of online CPU cores...
@@ -2875,7 +2721,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
     if (remaining_children_to_start > active_daemons_limit) {
         remaining_children_to_start = active_daemons_limit;
     }
-    if (!retained->is_graceful) {
+    if (!retained->mpm->was_graceful) {
         startup_children(remaining_children_to_start);
         remaining_children_to_start = 0;
     }
@@ -2893,12 +2739,12 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
     ap_log_command_line(plog, s);
     ap_log_mpm_common(s);
 
-    mpm_state = AP_MPMQ_RUNNING;
+    retained->mpm->mpm_state = AP_MPMQ_RUNNING;
 
     server_main_loop(remaining_children_to_start, num_buckets);
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
 
-    if (shutdown_pending && !retained->is_graceful) {
+    if (retained->mpm->shutdown_pending && retained->mpm->is_ungraceful) {
         /* Time to shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
@@ -2915,8 +2761,11 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
             ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
                          ap_server_conf, APLOGNO(00491) "caught SIGTERM, shutting down");
         }
+
         return DONE;
-    } else if (shutdown_pending) {
+    }
+
+    if (retained->mpm->shutdown_pending) {
         /* Time to gracefully shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
@@ -2946,7 +2795,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
         }
 
         /* Don't really exit until each child has finished */
-        shutdown_pending = 0;
+        retained->mpm->shutdown_pending = 0;
         do {
             /* Pause for a second */
             apr_sleep(apr_time_from_sec(1));
@@ -2962,7 +2811,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
                     break;
                 }
             }
-        } while (!shutdown_pending && active_children &&
+        } while (!retained->mpm->shutdown_pending && active_children &&
                  (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
 
         /* We might be here because we received SIGTERM, either
@@ -2979,8 +2828,6 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
     }
 
     /* we've been told to restart */
-    apr_signal(SIGHUP, SIG_IGN);
-
     if (one_process) {
         /* not worth thinking about */
         return DONE;
@@ -2990,10 +2837,10 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
     /* XXX: we really need to make sure this new generation number isn't in
      * use by any of the children.
      */
-    ++retained->my_generation;
-    ap_scoreboard_image->global->running_generation = retained->my_generation;
+    ++retained->mpm->my_generation;
+    ap_scoreboard_image->global->running_generation = retained->mpm->my_generation;
 
-    if (retained->is_graceful) {
+    if (!retained->mpm->is_ungraceful) {
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00493)
                      AP_SIG_GRACEFUL_STRING
                      " received.  Doing graceful restart");
@@ -3094,7 +2941,7 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog,
     pconf = p;
 
     /* the reverse of pre_config, we want this only the first time around */
-    if (retained->module_loads == 1) {
+    if (retained->mpm->module_loads == 1) {
         startup = 1;
         level_flags |= APLOG_STARTUP;
     }
@@ -3109,9 +2956,9 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog,
     if (one_process) {
         num_buckets = 1;
     }
-    else if (retained->is_graceful) {
+    else if (retained->mpm->was_graceful) {
         /* Preserve the number of buckets on graceful restarts. */
-        num_buckets = retained->num_buckets;
+        num_buckets = retained->mpm->num_buckets;
     }
     if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
                                      &listen_buckets, &num_buckets))) {
@@ -3133,25 +2980,25 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog,
         all_buckets[i].listeners = listen_buckets[i];
     }
 
-    if (retained->max_buckets < num_buckets) {
+    if (retained->mpm->max_buckets < num_buckets) {
         int new_max, *new_ptr;
-        new_max = retained->max_buckets * 2;
+        new_max = retained->mpm->max_buckets * 2;
         if (new_max < num_buckets) {
             new_max = num_buckets;
         }
         new_ptr = (int *)apr_palloc(ap_pglobal, new_max * sizeof(int));
         memcpy(new_ptr, retained->idle_spawn_rate,
-               retained->num_buckets * sizeof(int));
+               retained->mpm->num_buckets * sizeof(int));
         retained->idle_spawn_rate = new_ptr;
-        retained->max_buckets = new_max;
+        retained->mpm->max_buckets = new_max;
     }
-    if (retained->num_buckets < num_buckets) {
+    if (retained->mpm->num_buckets < num_buckets) {
         int rate_max = 1;
         /* If new buckets are added, set their idle spawn rate to
          * the highest so far, so that they get filled as quickly
          * as the existing ones.
          */
-        for (i = 0; i < retained->num_buckets; i++) {
+        for (i = 0; i < retained->mpm->num_buckets; i++) {
             if (rate_max < retained->idle_spawn_rate[i]) {
                 rate_max = retained->idle_spawn_rate[i];
             }
@@ -3160,7 +3007,7 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog,
             retained->idle_spawn_rate[i] = rate_max;
         }
     }
-    retained->num_buckets = num_buckets;
+    retained->mpm->num_buckets = num_buckets;
 
     /* for skiplist */
     srand((unsigned int)apr_time_now());
@@ -3173,8 +3020,7 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog,
     int no_detach, debug, foreground;
     apr_status_t rv;
     const char *userdata_key = "mpm_event_module";
-
-    mpm_state = AP_MPMQ_STARTING;
+    int test_atomics = 0;
 
     debug = ap_exists_config_define("DEBUG");
 
@@ -3188,15 +3034,24 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog,
         foreground = ap_exists_config_define("FOREGROUND");
     }
 
-    /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
         retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        retained->mpm = ap_unixd_mpm_get_retained_data();
         retained->max_daemons_limit = -1;
+        if (retained->mpm->module_loads) {
+            test_atomics = 1;
+        }
+    }
+    retained->mpm->mpm_state = AP_MPMQ_STARTING;
+    if (retained->mpm->baton != retained) {
+        retained->mpm->was_graceful = 0;
+        retained->mpm->baton = retained;
     }
-    ++retained->module_loads;
-    if (retained->module_loads == 2) {
-        /* test for correct operation of fdqueue */
+    ++retained->mpm->module_loads;
+
+    /* test once for correct operation of fdqueue */
+    if (test_atomics || retained->mpm->module_loads == 2) {
         static apr_uint32_t foo1, foo2;
 
         apr_atomic_set32(&foo1, 100);
@@ -3206,7 +3061,10 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog,
                          "atomics not working as expected - add32 of negative number");
             return HTTP_INTERNAL_SERVER_ERROR;
         }
+    }
 
+    /* sigh, want this only the second time around */
+    if (retained->mpm->module_loads == 2) {
         rv = apr_pollset_create(&event_pollset, 1, plog,
                                 APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY);
         if (rv != APR_SUCCESS) {
@@ -3317,7 +3175,7 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog,
     int startup = 0;
 
     /* the reverse of pre_config, we want this only the first time around */
-    if (retained->module_loads == 1) {
+    if (retained->mpm->module_loads == 1) {
         startup = 1;
     }
 
index 8bb46a3948f4ca9fce94ab2fbda611000dd702c8..46fbc86fa5c61660db4d580ac09d05531d17bea2 100644 (file)
@@ -93,17 +93,15 @@ static int ap_daemons_min_free=0;
 static int ap_daemons_max_free=0;
 static int ap_daemons_limit=0;      /* MaxRequestWorkers */
 static int server_limit = 0;
-static int mpm_state = AP_MPMQ_STARTING;
 
 /* data retained by prefork across load/unload of the module
  * allocated on first call to pre-config hook; located on
  * subsequent calls to pre-config hook
  */
 typedef struct prefork_retained_data {
+    ap_unixd_mpm_retained_data *mpm;
+
     int first_server_limit;
-    int module_loads;
-    ap_generation_t my_generation;
-    int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     /*
      * The max child slot ever assigned, preserved across restarts.  Necessary
@@ -130,7 +128,6 @@ typedef struct prefork_child_bucket {
     ap_listen_rec *listeners;
     apr_proc_mutex_t *mutex;
 } prefork_child_bucket;
-static int                   num_buckets; /* Number of listeners buckets */
 static prefork_child_bucket *all_buckets, /* All listeners buckets */
                             *my_bucket;   /* Current child bucket */
 
@@ -214,14 +211,14 @@ static void prefork_note_child_started(int slot, pid_t pid)
     ap_scoreboard_image->parent[slot].pid = pid;
     ap_run_child_status(ap_server_conf,
                         ap_scoreboard_image->parent[slot].pid,
-                        retained->my_generation, slot, MPM_CHILD_STARTED);
+                        retained->mpm->my_generation, slot, MPM_CHILD_STARTED);
 }
 
 /* a clean exit from a child with proper cleanup */
 static void clean_child_exit(int code) __attribute__ ((noreturn));
 static void clean_child_exit(int code)
 {
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
 
     if (pchild) {
         apr_pool_destroy(pchild);
@@ -242,7 +239,7 @@ static apr_status_t accept_mutex_on(void)
     if (rv != APR_SUCCESS) {
         const char *msg = "couldn't grab the accept mutex";
 
-        if (retained->my_generation !=
+        if (retained->mpm->my_generation !=
             ap_scoreboard_image->global->running_generation) {
             ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, APLOGNO(00143) "%s", msg);
             clean_child_exit(0);
@@ -261,7 +258,7 @@ static apr_status_t accept_mutex_off(void)
     if (rv != APR_SUCCESS) {
         const char *msg = "couldn't release the accept mutex";
 
-        if (retained->my_generation !=
+        if (retained->mpm->my_generation !=
             ap_scoreboard_image->global->running_generation) {
             ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, APLOGNO(00145) "%s", msg);
             /* don't exit here... we have a connection to
@@ -329,10 +326,10 @@ static int prefork_query(int query_code, int *result, apr_status_t *rv)
         *result = ap_daemons_limit;
         break;
     case AP_MPMQ_MPM_STATE:
-        *result = mpm_state;
+        *result = retained->mpm->mpm_state;
         break;
     case AP_MPMQ_GENERATION:
-        *result = retained->my_generation;
+        *result = retained->mpm->my_generation;
         break;
     default:
         *rv = APR_ENOTIMPL;
@@ -355,130 +352,18 @@ static void just_die(int sig)
     clean_child_exit(0);
 }
 
-/* volatile because they're updated from a signal handler */
-static int volatile shutdown_pending;
-static int volatile restart_pending;
+/* volatile because it's updated from a signal handler */
 static int volatile die_now = 0;
 
 static void stop_listening(int sig)
 {
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
     ap_close_listeners_ex(my_bucket->listeners);
 
     /* For a graceful stop, we want the child to exit when done */
     die_now = 1;
 }
 
-static void sig_term(int sig)
-{
-    if (shutdown_pending == 1) {
-        /* Um, is this _probably_ not an error, if the user has
-         * tried to do a shutdown twice quickly, so we won't
-         * worry about reporting it.
-         */
-        return;
-    }
-    mpm_state = AP_MPMQ_STOPPING;
-    shutdown_pending = 1;
-    retained->is_graceful = (sig == AP_SIG_GRACEFUL_STOP);
-}
-
-/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL
- * in the parent process, unless running in ONE_PROCESS mode
- */
-static void restart(int sig)
-{
-    if (restart_pending == 1) {
-        /* Probably not an error - don't bother reporting it */
-        return;
-    }
-    mpm_state = AP_MPMQ_STOPPING;
-    restart_pending = 1;
-    retained->is_graceful = (sig == AP_SIG_GRACEFUL);
-}
-
-static void set_signals(void)
-{
-#ifndef NO_USE_SIGACTION
-    struct sigaction sa;
-#endif
-
-    if (!one_process) {
-        ap_fatal_signal_setup(ap_server_conf, pconf);
-    }
-
-#ifndef NO_USE_SIGACTION
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-
-    sa.sa_handler = sig_term;
-    if (sigaction(SIGTERM, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00147) "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, APLOGNO(00148)
-                     "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, APLOGNO(00149) "sigaction(SIGINT)");
-#endif
-#ifdef SIGXCPU
-    sa.sa_handler = SIG_DFL;
-    if (sigaction(SIGXCPU, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00150) "sigaction(SIGXCPU)");
-#endif
-#ifdef SIGXFSZ
-    /* For systems following the LFS standard, ignoring SIGXFSZ allows
-     * a write() beyond the 2GB limit to fail gracefully with E2BIG
-     * rather than terminate the process. */
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGXFSZ, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00151) "sigaction(SIGXFSZ)");
-#endif
-#ifdef SIGPIPE
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGPIPE, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00152) "sigaction(SIGPIPE)");
-#endif
-
-    /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
-     * processing one
-     */
-    sigaddset(&sa.sa_mask, SIGHUP);
-    sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
-    sa.sa_handler = restart;
-    if (sigaction(SIGHUP, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00153) "sigaction(SIGHUP)");
-    if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00154) "sigaction(" AP_SIG_GRACEFUL_STRING ")");
-#else
-    if (!one_process) {
-#ifdef SIGXCPU
-        apr_signal(SIGXCPU, SIG_DFL);
-#endif /* SIGXCPU */
-#ifdef SIGXFSZ
-        apr_signal(SIGXFSZ, SIG_IGN);
-#endif /* SIGXFSZ */
-    }
-
-    apr_signal(SIGTERM, sig_term);
-#ifdef SIGHUP
-    apr_signal(SIGHUP, restart);
-#endif /* SIGHUP */
-#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 */
-
-#endif
-}
-
 /*****************************************************************
  * Child process main loop.
  * The following vars are static to avoid getting clobbered by longjmp();
@@ -505,9 +390,8 @@ static void child_main(int child_num_arg, int child_bucket)
     int last_poll_idx = 0;
     const char *lockfile;
 
-    mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
-                                   * child initializes
-                                   */
+    /* for benefit of any hooks that run as this child initializes */
+    retained->mpm->mpm_state = AP_MPMQ_STARTING;
 
     my_child_num = child_num_arg;
     ap_my_pid = getpid();
@@ -533,7 +417,7 @@ static void child_main(int child_num_arg, int child_bucket)
     apr_pool_tag(ptrans, "transaction");
 
     /* close unused listeners and pods */
-    for (i = 0; i < num_buckets; i++) {
+    for (i = 0; i < retained->mpm->num_buckets; i++) {
         if (i != child_bucket) {
             ap_close_listeners_ex(all_buckets[i].listeners);
             ap_mpm_pod_close(all_buckets[i].pod);
@@ -598,14 +482,17 @@ static void child_main(int child_num_arg, int child_bucket)
         lr->accept_func = ap_unixd_accept;
     }
 
-    mpm_state = AP_MPMQ_RUNNING;
+    retained->mpm->mpm_state = AP_MPMQ_RUNNING;
 
     bucket_alloc = apr_bucket_alloc_create(pchild);
 
     /* die_now is set when AP_SIG_GRACEFUL is received in the child;
-     * shutdown_pending is set when SIGTERM is received when running
-     * in single process mode.  */
-    while (!die_now && !shutdown_pending) {
+     * {shutdown,restart}_pending are set when a signal is received while
+     * running in single process mode.
+     */
+    while (!die_now
+           && !retained->mpm->shutdown_pending
+           && !retained->mpm->restart_pending) {
         conn_rec *current_conn;
         void *csd;
 
@@ -643,7 +530,8 @@ static void child_main(int child_num_arg, int child_bucket)
                  * poll if already signalled
                  */
                 if (die_now         /* in graceful stop/restart */
-                    || (one_process && shutdown_pending)) {
+                        || retained->mpm->shutdown_pending
+                        || retained->mpm->restart_pending) {
                     SAFE_ACCEPT(accept_mutex_off());
                     clean_child_exit(0);
                 }
@@ -732,7 +620,7 @@ static void child_main(int child_num_arg, int child_bucket)
         if (ap_mpm_pod_check(my_bucket->pod) == APR_SUCCESS) { /* selected as idle? */
             die_now = 1;
         }
-        else if (retained->my_generation !=
+        else if (retained->mpm->my_generation !=
                  ap_scoreboard_image->global->running_generation) { /* restart? */
             /* yeah, this could be non-graceful restart, in which case the
              * parent will kill us soon enough, but why bother checking?
@@ -756,13 +644,6 @@ static int make_child(server_rec *s, int slot, int bucket)
     if (one_process) {
         my_bucket = &all_buckets[0];
 
-        apr_signal(SIGHUP, sig_term);
-        /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */
-        apr_signal(SIGINT, sig_term);
-#ifdef SIGQUIT
-        apr_signal(SIGQUIT, SIG_DFL);
-#endif
-        apr_signal(SIGTERM, sig_term);
         prefork_note_child_started(slot, getpid());
         child_main(slot, 0);
         /* NOTREACHED */
@@ -840,7 +721,7 @@ static void startup_children(int number_to_start)
         if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
             continue;
         }
-        if (make_child(ap_server_conf, i, i % num_buckets) < 0) {
+        if (make_child(ap_server_conf, i, i % retained->mpm->num_buckets) < 0) {
             break;
         }
         --number_to_start;
@@ -901,7 +782,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p)
          * shut down gracefully, in case it happened to pick up a request
          * while we were counting
          */
-        bucket_kill_child_record = (bucket_kill_child_record + 1) % num_buckets;
+        bucket_kill_child_record = (bucket_kill_child_record + 1) % retained->mpm->num_buckets;
         ap_mpm_pod_signal(all_buckets[bucket_kill_child_record].pod);
         retained->idle_spawn_rate = 1;
     }
@@ -928,7 +809,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p)
             }
             for (i = 0; i < free_length; ++i) {
                 bucket_make_child_record++;
-                bucket_make_child_record %= num_buckets;
+                bucket_make_child_record %= retained->mpm->num_buckets;
                 make_child(ap_server_conf, free_slots[i],
                            bucket_make_child_record);
             }
@@ -960,19 +841,21 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
 
     ap_log_pid(pconf, ap_pid_fname);
 
-    if (!retained->is_graceful) {
+    if (!retained->mpm->was_graceful) {
         if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
-            mpm_state = AP_MPMQ_STOPPING;
+            retained->mpm->mpm_state = AP_MPMQ_STOPPING;
             return !OK;
         }
         /* fix the generation number in the global score; we just got a new,
          * cleared scoreboard
          */
-        ap_scoreboard_image->global->running_generation = retained->my_generation;
+        ap_scoreboard_image->global->running_generation = retained->mpm->my_generation;
     }
 
-    restart_pending = shutdown_pending = 0;
-    set_signals();
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
+    ap_unixd_mpm_set_signals(pconf, one_process);
 
     if (one_process) {
         AP_MONCONTROL(1);
@@ -985,14 +868,14 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     /* Don't thrash since num_buckets depends on the
      * system and the number of online CPU cores...
      */
-    if (ap_daemons_limit < num_buckets)
-        ap_daemons_limit = num_buckets;
-    if (ap_daemons_to_start < num_buckets)
-        ap_daemons_to_start = num_buckets;
-    if (ap_daemons_min_free < num_buckets)
-        ap_daemons_min_free = num_buckets;
-    if (ap_daemons_max_free < ap_daemons_min_free + num_buckets)
-        ap_daemons_max_free = ap_daemons_min_free + num_buckets;
+    if (ap_daemons_limit < retained->mpm->num_buckets)
+        ap_daemons_limit = retained->mpm->num_buckets;
+    if (ap_daemons_to_start < retained->mpm->num_buckets)
+        ap_daemons_to_start = retained->mpm->num_buckets;
+    if (ap_daemons_min_free < retained->mpm->num_buckets)
+        ap_daemons_min_free = retained->mpm->num_buckets;
+    if (ap_daemons_max_free < ap_daemons_min_free + retained->mpm->num_buckets)
+        ap_daemons_max_free = ap_daemons_min_free + retained->mpm->num_buckets;
 
     /* If we're doing a graceful_restart then we're going to see a lot
      * of children exiting immediately when we get into the main loop
@@ -1006,7 +889,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     if (remaining_children_to_start > ap_daemons_limit) {
         remaining_children_to_start = ap_daemons_limit;
     }
-    if (!retained->is_graceful) {
+    if (!retained->mpm->was_graceful) {
         startup_children(remaining_children_to_start);
         remaining_children_to_start = 0;
     }
@@ -1031,9 +914,9 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                     : "none",
                 apr_proc_mutex_defname());
 
-    mpm_state = AP_MPMQ_RUNNING;
+    retained->mpm->mpm_state = AP_MPMQ_RUNNING;
 
-    while (!restart_pending && !shutdown_pending) {
+    while (!retained->mpm->restart_pending && !retained->mpm->shutdown_pending) {
         int child_slot;
         apr_exit_why_e exitwhy;
         int status, processed_status;
@@ -1057,8 +940,8 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                  */
                 if (child_slot < 0
                     || ap_get_scoreboard_process(child_slot)->generation
-                       == retained->my_generation) {
-                    mpm_state = AP_MPMQ_STOPPING;
+                       == retained->mpm->my_generation) {
+                    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
                     return !OK;
                 }
                 else {
@@ -1095,7 +978,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                 /* handled */
 #endif
             }
-            else if (retained->is_graceful) {
+            else if (retained->mpm->was_graceful) {
                 /* Great, we've probably just lost a slot in the
                  * scoreboard.  Somehow we don't know about this
                  * child.
@@ -1128,9 +1011,9 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
         perform_idle_server_maintenance(pconf);
     }
 
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
 
-    if (shutdown_pending && !retained->is_graceful) {
+    if (retained->mpm->shutdown_pending && retained->mpm->is_ungraceful) {
         /* Time to shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
@@ -1146,7 +1029,9 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                     "caught SIGTERM, shutting down");
 
         return DONE;
-    } else if (shutdown_pending) {
+    }
+
+    if (retained->mpm->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
@@ -1159,7 +1044,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
         ap_close_listeners();
 
         /* kill off the idle ones */
-        for (i = 0; i < num_buckets; i++) {
+        for (i = 0; i < retained->mpm->num_buckets; i++) {
             ap_mpm_pod_killpg(all_buckets[i].pod, retained->max_daemons_limit);
         }
 
@@ -1187,7 +1072,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
         }
 
         /* Don't really exit until each child has finished */
-        shutdown_pending = 0;
+        retained->mpm->shutdown_pending = 0;
         do {
             /* Pause for a second */
             sleep(1);
@@ -1203,7 +1088,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                     break;
                 }
             }
-        } while (!shutdown_pending && active_children &&
+        } while (!retained->mpm->shutdown_pending && active_children &&
                  (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
 
         /* We might be here because we received SIGTERM, either
@@ -1216,8 +1101,6 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     }
 
     /* we've been told to restart */
-    apr_signal(SIGHUP, SIG_IGN);
-    apr_signal(AP_SIG_GRACEFUL, SIG_IGN);
     if (one_process) {
         /* not worth thinking about */
         return DONE;
@@ -1227,15 +1110,15 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     /* XXX: we really need to make sure this new generation number isn't in
      * use by any of the children.
      */
-    ++retained->my_generation;
-    ap_scoreboard_image->global->running_generation = retained->my_generation;
+    ++retained->mpm->my_generation;
+    ap_scoreboard_image->global->running_generation = retained->mpm->my_generation;
 
-    if (retained->is_graceful) {
+    if (!retained->mpm->is_ungraceful) {
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00171)
                     "Graceful restart requested, doing restart");
 
         /* kill off the idle ones */
-        for (i = 0; i < num_buckets; i++) {
+        for (i = 0; i < retained->mpm->num_buckets; i++) {
             ap_mpm_pod_killpg(all_buckets[i].pod, retained->max_daemons_limit);
         }
 
@@ -1287,7 +1170,7 @@ static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
     pconf = p;
 
     /* the reverse of pre_config, we want this only the first time around */
-    if (retained->module_loads == 1) {
+    if (retained->mpm->module_loads == 1) {
         startup = 1;
         level_flags |= APLOG_STARTUP;
     }
@@ -1300,22 +1183,22 @@ static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
     }
 
     if (one_process) {
-        num_buckets = 1;
+        retained->mpm->num_buckets = 1;
     }
-    else if (!retained->is_graceful) { /* Preserve the number of buckets
-                                          on graceful restarts. */
-        num_buckets = 0;
+    else if (!retained->mpm->was_graceful) {
+        /* Preserve the number of buckets on graceful restarts. */
+        retained->mpm->num_buckets = 0;
     }
     if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
-                                     &listen_buckets, &num_buckets))) {
+                                     &listen_buckets, &retained->mpm->num_buckets))) {
         ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
                      (startup ? NULL : s),
                      "could not duplicate listeners");
         return !OK;
     }
-    all_buckets = apr_pcalloc(pconf, num_buckets *
+    all_buckets = apr_pcalloc(pconf, retained->mpm->num_buckets *
                                      sizeof(prefork_child_bucket));
-    for (i = 0; i < num_buckets; i++) {
+    for (i = 0; i < retained->mpm->num_buckets; i++) {
         if ((rv = ap_mpm_pod_open(pconf, &all_buckets[i].pod))) {
             ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
                          (startup ? NULL : s),
@@ -1344,8 +1227,6 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp
     apr_status_t rv;
     const char *userdata_key = "mpm_prefork_module";
 
-    mpm_state = AP_MPMQ_STARTING;
-
     debug = ap_exists_config_define("DEBUG");
 
     if (debug) {
@@ -1361,15 +1242,22 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp
 
     ap_mutex_register(p, AP_ACCEPT_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0);
 
-    /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
         retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        retained->mpm = ap_unixd_mpm_get_retained_data();
         retained->max_daemons_limit = -1;
         retained->idle_spawn_rate = 1;
     }
-    ++retained->module_loads;
-    if (retained->module_loads == 2) {
+    retained->mpm->mpm_state = AP_MPMQ_STARTING;
+    if (retained->mpm->baton != retained) {
+        retained->mpm->was_graceful = 0;
+        retained->mpm->baton = retained;
+    }
+    ++retained->mpm->module_loads;
+
+    /* sigh, want this only the second time around */
+    if (retained->mpm->module_loads == 2) {
         if (!one_process && !foreground) {
             /* before we detach, setup crash handlers to log to errorlog */
             ap_fatal_signal_setup(ap_server_conf, pconf);
@@ -1402,7 +1290,7 @@ static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog,
     int startup = 0;
 
     /* the reverse of pre_config, we want this only the first time around */
-    if (retained->module_loads == 1) {
+    if (retained->mpm->module_loads == 1) {
         startup = 1;
     }
 
index 73c33bfabc65bde72ec83b57a8666496ecbd98d7..7fccd0281a6182b2fc1b93df892b279d6cb29b79 100644 (file)
@@ -134,19 +134,17 @@ static int num_listensocks = 0;
 static int resource_shortage = 0;
 static fd_queue_t *worker_queue;
 static fd_queue_info_t *worker_queue_info;
-static int mpm_state = AP_MPMQ_STARTING;
 
 /* data retained by worker across load/unload of the module
  * allocated on first call to pre-config hook; located on
  * subsequent calls to pre-config hook
  */
 typedef struct worker_retained_data {
+    ap_unixd_mpm_retained_data *mpm;
+
     int first_server_limit;
     int first_thread_limit;
-    int module_loads;
     int sick_child_detected;
-    ap_generation_t my_generation;
-    int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     int near_maxclients_reported;
     /*
@@ -167,12 +165,6 @@ typedef struct worker_retained_data {
 #define MAX_SPAWN_RATE        (32)
 #endif
     int hold_off_on_exponential_spawning;
-    /*
-     * Current number of listeners buckets and maximum reached across
-     * restarts (to size retained data according to dynamic num_buckets,
-     * eg. idle_spawn_rate).
-     */
-    int num_buckets, max_buckets;
 } worker_retained_data;
 static worker_retained_data *retained;
 
@@ -313,7 +305,7 @@ static void signal_threads(int mode)
         return;
     }
     terminate_mode = mode;
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
 
     /* in case we weren't called from the listener thread, wake up the
      * listener thread
@@ -372,10 +364,10 @@ static int worker_query(int query_code, int *result, apr_status_t *rv)
             *result = ap_daemons_limit;
             break;
         case AP_MPMQ_MPM_STATE:
-            *result = mpm_state;
+            *result = retained->mpm->mpm_state;
             break;
         case AP_MPMQ_GENERATION:
-            *result = retained->my_generation;
+            *result = retained->mpm->my_generation;
             break;
         default:
             *rv = APR_ENOTIMPL;
@@ -403,7 +395,7 @@ static void worker_note_child_started(int slot, pid_t pid)
     ap_scoreboard_image->parent[slot].pid = pid;
     ap_run_child_status(ap_server_conf,
                         ap_scoreboard_image->parent[slot].pid,
-                        retained->my_generation, slot, MPM_CHILD_STARTED);
+                        retained->mpm->my_generation, slot, MPM_CHILD_STARTED);
 }
 
 static void worker_note_child_lost_slot(int slot, pid_t newpid)
@@ -436,7 +428,7 @@ static const char *worker_get_name(void)
 static void clean_child_exit(int code) __attribute__ ((noreturn));
 static void clean_child_exit(int code)
 {
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
     if (pchild) {
         apr_pool_destroy(pchild);
     }
@@ -459,153 +451,6 @@ static void just_die(int sig)
 
 static int child_fatal;
 
-/* volatile because they're updated from a signal handler */
-static int volatile shutdown_pending;
-static int volatile restart_pending;
-
-/*
- * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
- * functions to initiate shutdown or restart without relying on signals.
- * Previously this was initiated in sig_term() and restart() signal handlers,
- * but we want to be able to start a shutdown/restart from other sources --
- * e.g. on Win32, from the service manager. Now the service manager can
- * call ap_start_shutdown() or ap_start_restart() as appropriate.  Note that
- * these functions can also be called by the child processes, since global
- * variables are no longer used to pass on the required action to the parent.
- *
- * These should only be called from the parent process itself, since the
- * parent process will use the shutdown_pending and restart_pending variables
- * to determine whether to shutdown or restart. The child process should
- * call signal_parent() directly to tell the parent to die -- this will
- * cause neither of those variable to be set, which the parent will
- * assume means something serious is wrong (which it will be, for the
- * child to force an exit) and so do an exit anyway.
- */
-
-static void ap_start_shutdown(int graceful)
-{
-    mpm_state = AP_MPMQ_STOPPING;
-    if (shutdown_pending == 1) {
-        /* Um, is this _probably_ not an error, if the user has
-         * tried to do a shutdown twice quickly, so we won't
-         * worry about reporting it.
-         */
-        return;
-    }
-    shutdown_pending = 1;
-    retained->is_graceful = graceful;
-}
-
-/* do a graceful restart if graceful == 1 */
-static void ap_start_restart(int graceful)
-{
-    mpm_state = AP_MPMQ_STOPPING;
-    if (restart_pending == 1) {
-        /* Probably not an error - don't bother reporting it */
-        return;
-    }
-    restart_pending = 1;
-    retained->is_graceful = graceful;
-}
-
-static void sig_term(int sig)
-{
-    ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
-}
-
-static void restart(int sig)
-{
-    ap_start_restart(sig == AP_SIG_GRACEFUL);
-}
-
-static void set_signals(void)
-{
-#ifndef NO_USE_SIGACTION
-    struct sigaction sa;
-#endif
-
-    if (!one_process) {
-        ap_fatal_signal_setup(ap_server_conf, pconf);
-    }
-
-#ifndef NO_USE_SIGACTION
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-
-    sa.sa_handler = sig_term;
-    if (sigaction(SIGTERM, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00264)
-                     "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, APLOGNO(00265)
-                     "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, APLOGNO(00266)
-                     "sigaction(SIGINT)");
-#endif
-#ifdef SIGXCPU
-    sa.sa_handler = SIG_DFL;
-    if (sigaction(SIGXCPU, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00267)
-                     "sigaction(SIGXCPU)");
-#endif
-#ifdef SIGXFSZ
-    /* For systems following the LFS standard, ignoring SIGXFSZ allows
-     * a write() beyond the 2GB limit to fail gracefully with E2BIG
-     * rather than terminate the process. */
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGXFSZ, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00268)
-                     "sigaction(SIGXFSZ)");
-#endif
-#ifdef SIGPIPE
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGPIPE, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00269)
-                     "sigaction(SIGPIPE)");
-#endif
-
-    /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
-     * processing one */
-    sigaddset(&sa.sa_mask, SIGHUP);
-    sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
-    sa.sa_handler = restart;
-    if (sigaction(SIGHUP, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00270)
-                     "sigaction(SIGHUP)");
-    if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00271)
-                     "sigaction(" AP_SIG_GRACEFUL_STRING ")");
-#else
-    if (!one_process) {
-#ifdef SIGXCPU
-        apr_signal(SIGXCPU, SIG_DFL);
-#endif /* SIGXCPU */
-#ifdef SIGXFSZ
-        apr_signal(SIGXFSZ, SIG_IGN);
-#endif /* SIGXFSZ */
-    }
-
-    apr_signal(SIGTERM, sig_term);
-#ifdef SIGHUP
-    apr_signal(SIGHUP, restart);
-#endif /* SIGHUP */
-#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 */
-
-#endif
-}
-
 /*****************************************************************
  * Here follows a long bunch of generic server bookkeeping stuff...
  */
@@ -927,7 +772,7 @@ static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy)
 
     ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
     ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current();
-    ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation;
+    ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->mpm->my_generation;
     ap_update_child_status_from_indexes(process_slot, thread_slot,
                                         SERVER_STARTING, NULL);
 
@@ -1233,15 +1078,15 @@ static void child_main(int child_num_arg, int child_bucket)
     apr_thread_t *start_thread_id;
     int i;
 
-    mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
-                                   * child initializes
-                                   */
+    /* for benefit of any hooks that run as this child initializes */
+    retained->mpm->mpm_state = AP_MPMQ_STARTING;
+
     ap_my_pid = getpid();
     ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
     /* close unused listeners and pods */
-    for (i = 0; i < retained->num_buckets; i++) {
+    for (i = 0; i < retained->mpm->num_buckets; i++) {
         if (i != child_bucket) {
             ap_close_listeners_ex(all_buckets[i].listeners);
             ap_mpm_podx_close(all_buckets[i].pod);
@@ -1324,7 +1169,7 @@ static void child_main(int child_num_arg, int child_bucket)
         clean_child_exit(APEXIT_CHILDSICK);
     }
 
-    mpm_state = AP_MPMQ_RUNNING;
+    retained->mpm->mpm_state = AP_MPMQ_RUNNING;
 
     /* If we are only running in one_process mode, we will want to
      * still handle signals. */
@@ -1410,7 +1255,6 @@ static int make_child(server_rec *s, int slot, int bucket)
     if (one_process) {
         my_bucket = &all_buckets[0];
 
-        set_signals();
         worker_note_child_started(slot, getpid());
         child_main(slot, 0);
         /* NOTREACHED */
@@ -1481,7 +1325,7 @@ static void startup_children(int number_to_start)
         if (ap_scoreboard_image->parent[i].pid != 0) {
             continue;
         }
-        if (make_child(ap_server_conf, i, i % retained->num_buckets) < 0) {
+        if (make_child(ap_server_conf, i, i % retained->mpm->num_buckets) < 0) {
             break;
         }
         --number_to_start;
@@ -1547,7 +1391,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
                                    loop if no pid?  not much else matters */
                 if (status <= SERVER_READY &&
                         !ps->quiescing &&
-                        ps->generation == retained->my_generation &&
+                        ps->generation == retained->mpm->my_generation &&
                         ps->bucket == child_bucket) {
                     ++idle_thread_count;
                 }
@@ -1601,7 +1445,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets)
         else {
             /* looks like a basket case, as no child ever fully initialized; give up.
              */
-            shutdown_pending = 1;
+            retained->mpm->shutdown_pending = 1;
             child_fatal = 1;
             ap_log_error(APLOG_MARK, APLOG_ALERT, 0,
                          ap_server_conf, APLOGNO(02325)
@@ -1697,7 +1541,7 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
     apr_proc_t pid;
     int i;
 
-    while (!restart_pending && !shutdown_pending) {
+    while (!retained->mpm->restart_pending && !retained->mpm->shutdown_pending) {
         ap_wait_or_timeout(&exitwhy, &status, &pid, pconf, ap_server_conf);
 
         if (pid.pid != -1) {
@@ -1711,8 +1555,8 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
                  */
                 if (child_slot < 0
                     || ap_get_scoreboard_process(child_slot)->generation
-                       == retained->my_generation) {
-                    shutdown_pending = 1;
+                       == retained->mpm->my_generation) {
+                    retained->mpm->shutdown_pending = 1;
                     child_fatal = 1;
                     return;
                 }
@@ -1758,7 +1602,7 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
                 worker_note_child_killed(-1, /* already out of the scoreboard */
                                          pid.pid, old_gen);
                 if (processed_status == APEXIT_CHILDSICK
-                    && old_gen == retained->my_generation) {
+                    && old_gen == retained->mpm->my_generation) {
                     /* resource shortage, minimize the fork rate */
                     for (i = 0; i < num_buckets; i++) {
                         retained->idle_spawn_rate[i] = 1;
@@ -1771,7 +1615,7 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
                 /* handled */
 #endif
             }
-            else if (retained->is_graceful) {
+            else if (retained->mpm->was_graceful) {
                 /* Great, we've probably just lost a slot in the
                  * scoreboard.  Somehow we don't know about this child.
                  */
@@ -1809,25 +1653,27 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets)
 
 static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
 {
-    int num_buckets = retained->num_buckets;
+    int num_buckets = retained->mpm->num_buckets;
     int remaining_children_to_start;
     int i;
 
     ap_log_pid(pconf, ap_pid_fname);
 
-    if (!retained->is_graceful) {
+    if (!retained->mpm->was_graceful) {
         if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
-            mpm_state = AP_MPMQ_STOPPING;
+            retained->mpm->mpm_state = AP_MPMQ_STOPPING;
             return !OK;
         }
         /* fix the generation number in the global score; we just got a new,
          * cleared scoreboard
          */
-        ap_scoreboard_image->global->running_generation = retained->my_generation;
+        ap_scoreboard_image->global->running_generation = retained->mpm->my_generation;
     }
 
-    restart_pending = shutdown_pending = 0;
-    set_signals();
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
+    ap_unixd_mpm_set_signals(pconf, one_process);
 
     /* Don't thrash since num_buckets depends on the
      * system and the number of online CPU cores...
@@ -1860,7 +1706,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     if (remaining_children_to_start > ap_daemons_limit) {
         remaining_children_to_start = ap_daemons_limit;
     }
-    if (!retained->is_graceful) {
+    if (!retained->mpm->was_graceful) {
         startup_children(remaining_children_to_start);
         remaining_children_to_start = 0;
     }
@@ -1883,12 +1729,12 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                     ? apr_proc_mutex_name(all_buckets[0].mutex)
                     : "none",
                 apr_proc_mutex_defname());
-    mpm_state = AP_MPMQ_RUNNING;
+    retained->mpm->mpm_state = AP_MPMQ_RUNNING;
 
     server_main_loop(remaining_children_to_start, num_buckets);
-    mpm_state = AP_MPMQ_STOPPING;
+    retained->mpm->mpm_state = AP_MPMQ_STOPPING;
 
-    if (shutdown_pending && !retained->is_graceful) {
+    if (retained->mpm->shutdown_pending && retained->mpm->is_ungraceful) {
         /* Time to shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
@@ -1906,7 +1752,9 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                          ap_server_conf, APLOGNO(00295) "caught SIGTERM, shutting down");
         }
         return DONE;
-    } else if (shutdown_pending) {
+    }
+
+    if (retained->mpm->shutdown_pending) {
         /* Time to gracefully shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
@@ -1937,7 +1785,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
         }
 
         /* Don't really exit until each child has finished */
-        shutdown_pending = 0;
+        retained->mpm->shutdown_pending = 0;
         do {
             /* Pause for a second */
             apr_sleep(apr_time_from_sec(1));
@@ -1953,7 +1801,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
                     break;
                 }
             }
-        } while (!shutdown_pending && active_children &&
+        } while (!retained->mpm->shutdown_pending && active_children &&
                  (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
 
         /* We might be here because we received SIGTERM, either
@@ -1970,8 +1818,6 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     }
 
     /* we've been told to restart */
-    apr_signal(SIGHUP, SIG_IGN);
-
     if (one_process) {
         /* not worth thinking about */
         return DONE;
@@ -1981,10 +1827,10 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     /* XXX: we really need to make sure this new generation number isn't in
      * use by any of the children.
      */
-    ++retained->my_generation;
-    ap_scoreboard_image->global->running_generation = retained->my_generation;
+    ++retained->mpm->my_generation;
+    ap_scoreboard_image->global->running_generation = retained->mpm->my_generation;
 
-    if (retained->is_graceful) {
+    if (!retained->mpm->is_ungraceful) {
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00297)
                      AP_SIG_GRACEFUL_STRING " received.  Doing graceful restart");
         /* wake up the children...time to die.  But we'll have more soon */
@@ -2033,7 +1879,7 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
     pconf = p;
 
     /* the reverse of pre_config, we want this only the first time around */
-    if (retained->module_loads == 1) {
+    if (retained->mpm->module_loads == 1) {
         startup = 1;
         level_flags |= APLOG_STARTUP;
     }
@@ -2048,9 +1894,9 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
     if (one_process) {
         num_buckets = 1;
     }
-    else if (retained->is_graceful) {
+    else if (retained->mpm->was_graceful) {
         /* Preserve the number of buckets on graceful restarts. */
-        num_buckets = retained->num_buckets;
+        num_buckets = retained->mpm->num_buckets;
     }
     if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
                                      &listen_buckets, &num_buckets))) {
@@ -2082,25 +1928,25 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
         all_buckets[i].listeners = listen_buckets[i];
     }
 
-    if (retained->max_buckets < num_buckets) {
+    if (retained->mpm->max_buckets < num_buckets) {
         int new_max, *new_ptr;
-        new_max = retained->max_buckets * 2;
+        new_max = retained->mpm->max_buckets * 2;
         if (new_max < num_buckets) {
             new_max = num_buckets;
         }
         new_ptr = (int *)apr_palloc(ap_pglobal, new_max * sizeof(int));
         memcpy(new_ptr, retained->idle_spawn_rate,
-               retained->num_buckets * sizeof(int));
+               retained->mpm->num_buckets * sizeof(int));
         retained->idle_spawn_rate = new_ptr;
-        retained->max_buckets = new_max;
+        retained->mpm->max_buckets = new_max;
     }
-    if (retained->num_buckets < num_buckets) {
+    if (retained->mpm->num_buckets < num_buckets) {
         int rate_max = 1;
         /* If new buckets are added, set their idle spawn rate to
          * the highest so far, so that they get filled as quickly
          * as the existing ones.
          */
-        for (i = 0; i < retained->num_buckets; i++) {
+        for (i = 0; i < retained->mpm->num_buckets; i++) {
             if (rate_max < retained->idle_spawn_rate[i]) {
                 rate_max = retained->idle_spawn_rate[i];
             }
@@ -2109,7 +1955,7 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
             retained->idle_spawn_rate[i] = rate_max;
         }
     }
-    retained->num_buckets = num_buckets;
+    retained->mpm->num_buckets = num_buckets;
 
     return OK;
 }
@@ -2121,8 +1967,6 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
     apr_status_t rv;
     const char *userdata_key = "mpm_worker_module";
 
-    mpm_state = AP_MPMQ_STARTING;
-
     debug = ap_exists_config_define("DEBUG");
 
     if (debug) {
@@ -2137,14 +1981,21 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
 
     ap_mutex_register(pconf, AP_ACCEPT_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0);
 
-    /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
         retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        retained->mpm = ap_unixd_mpm_get_retained_data();
         retained->max_daemons_limit = -1;
     }
-    ++retained->module_loads;
-    if (retained->module_loads == 2) {
+    retained->mpm->mpm_state = AP_MPMQ_STARTING;
+    if (retained->mpm->baton != retained) {
+        retained->mpm->was_graceful = 0;
+        retained->mpm->baton = retained;
+    }
+    ++retained->mpm->module_loads;
+
+    /* sigh, want this only the second time around */
+    if (retained->mpm->module_loads == 2) {
         if (!one_process && !foreground) {
             /* before we detach, setup crash handlers to log to errorlog */
             ap_fatal_signal_setup(ap_server_conf, pconf);
@@ -2181,7 +2032,7 @@ static int worker_check_config(apr_pool_t *p, apr_pool_t *plog,
     int startup = 0;
 
     /* the reverse of pre_config, we want this only the first time around */
-    if (retained->module_loads == 1) {
+    if (retained->mpm->module_loads == 1) {
         startup = 1;
     }
 
index dce10a78cffbe3289a7b3edf400438331a0def5c..2f3d20e4dfe793a1ff31af1779adb0fd04b79e4f 100644 (file)
@@ -1015,14 +1015,13 @@ AP_DECLARE(apr_status_t) ap_fatal_signal_setup(server_rec *s,
 #ifndef NO_USE_SIGACTION
     struct sigaction sa;
 
+    memset(&sa, 0, sizeof sa);
     sigemptyset(&sa.sa_mask);
 
 #if defined(SA_ONESHOT)
     sa.sa_flags = SA_ONESHOT;
 #elif defined(SA_RESETHAND)
     sa.sa_flags = SA_RESETHAND;
-#else
-    sa.sa_flags = 0;
 #endif
 
     sa.sa_handler = sig_coredump;