diff options
author | Yann Ylavic <ylavic@apache.org> | 2017-02-21 10:07:42 +0100 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2017-02-21 10:07:42 +0100 |
commit | f46d03312ee62d1b3901900108bf6bebbb805def (patch) | |
tree | 2c290facb93daac3a69241b6ea6b9d4fdb540298 /server | |
parent | mod_cache: Fix a regression in 2.4.25 for the forward proxy case by (diff) | |
download | apache2-f46d03312ee62d1b3901900108bf6bebbb805def.tar.xz apache2-f46d03312ee62d1b3901900108bf6bebbb805def.zip |
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.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1783849 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server')
-rw-r--r-- | server/mpm/event/event.c | 280 | ||||
-rw-r--r-- | server/mpm/motorz/motorz.c | 254 | ||||
-rw-r--r-- | server/mpm/motorz/motorz.h | 5 | ||||
-rw-r--r-- | server/mpm/prefork/prefork.c | 268 | ||||
-rw-r--r-- | server/mpm/worker/worker.c | 273 | ||||
-rw-r--r-- | server/mpm_unix.c | 3 |
6 files changed, 284 insertions, 799 deletions
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index bd89d033f7..d1014002f5 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -197,7 +197,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; @@ -382,12 +381,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 @@ -415,12 +413,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; @@ -566,7 +558,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 @@ -631,10 +623,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; case AP_MPMQ_CAN_SUSPEND: *result = 1; @@ -668,7 +660,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) @@ -680,7 +672,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); } @@ -703,10 +695,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_; @@ -729,149 +717,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); @@ -2341,7 +2186,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); @@ -2701,15 +2546,15 @@ static void child_main(int child_num_arg, int child_bucket) apr_pool_t *pskip; 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); @@ -2787,7 +2632,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. */ @@ -2884,7 +2729,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 */ @@ -2952,7 +2796,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; @@ -2997,7 +2841,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; @@ -3026,7 +2870,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) @@ -3138,7 +2982,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) { @@ -3152,8 +2996,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 @@ -3208,7 +3052,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. */ @@ -3246,25 +3090,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... @@ -3297,7 +3143,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; } @@ -3315,12 +3161,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... */ @@ -3337,8 +3183,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... */ @@ -3368,7 +3217,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)); @@ -3384,7 +3233,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 @@ -3401,8 +3250,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; @@ -3412,10 +3259,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"); @@ -3516,7 +3363,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; } @@ -3531,9 +3378,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))) { @@ -3555,25 +3402,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]; } @@ -3582,7 +3429,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()); @@ -3595,8 +3442,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"); @@ -3610,15 +3456,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); @@ -3628,7 +3483,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) { @@ -3739,7 +3597,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; } diff --git a/server/mpm/motorz/motorz.c b/server/mpm/motorz/motorz.c index 065dff1012..ac47e5fd96 100644 --- a/server/mpm/motorz/motorz.c +++ b/server/mpm/motorz/motorz.c @@ -23,7 +23,6 @@ static motorz_core_t *g_motorz_core; static int threads_per_child = 16; static int ap_num_kids = DEFAULT_START_DAEMON; static int thread_limit = MAX_THREAD_LIMIT/10; -static int mpm_state = AP_MPMQ_STARTING; /* one_process --- debugging mode variable; can be set from the command line * with the -X flag. If set, this gets you the child_main loop running @@ -43,7 +42,6 @@ static apr_pool_t *pchild; /* Pool for httpd child stuff */ static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ static pid_t parent_pid; static int my_child_num; -static int num_buckets; /* Number of listeners buckets */ static motorz_child_bucket *all_buckets, /* All listeners buckets */ *my_bucket; /* Current child bucket */ @@ -579,13 +577,15 @@ static void motorz_note_child_started(motorz_core_t *mz, 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, - mz->my_generation, slot, MPM_CHILD_STARTED); + mz->mpm->my_generation, slot, MPM_CHILD_STARTED); } /* a clean exit from a child with proper cleanup */ static void clean_child_exit(int code) { - mpm_state = AP_MPMQ_STOPPING; + motorz_core_t *mz = motorz_core_get(); + + mz->mpm->mpm_state = AP_MPMQ_STOPPING; apr_signal(SIGHUP, SIG_IGN); apr_signal(SIGTERM, SIG_IGN); @@ -610,7 +610,7 @@ static apr_status_t accept_mutex_on(void) if (rv != APR_SUCCESS) { const char *msg = "couldn't grab the accept mutex"; - if (mz->my_generation != + if (mz->mpm->my_generation != ap_scoreboard_image->global->running_generation) { ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, APLOGNO(02855) "%s", msg); clean_child_exit(0); @@ -630,7 +630,7 @@ static apr_status_t accept_mutex_off(void) if (rv != APR_SUCCESS) { const char *msg = "couldn't release the accept mutex"; - if (mz->my_generation != + if (mz->mpm->my_generation != ap_scoreboard_image->global->running_generation) { ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, APLOGNO(02857) "%s", msg); /* don't exit here... we have a connection to @@ -703,10 +703,10 @@ static int motorz_query(int query_code, int *result, apr_status_t *rv) *result = ap_num_kids; break; case AP_MPMQ_MPM_STATE: - *result = mpm_state; + *result = mz->mpm->mpm_state; break; case AP_MPMQ_GENERATION: - *result = mz->my_generation; + *result = mz->mpm->my_generation; break; default: *rv = APR_ENOTIMPL; @@ -729,132 +729,20 @@ 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; + motorz_core_t *mz = motorz_core_get(); + + mz->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) -{ - motorz_core_t *mz = motorz_core_get(); - 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; - mz->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) -{ - motorz_core_t *mz = motorz_core_get(); - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - mpm_state = AP_MPMQ_STOPPING; - restart_pending = 1; - mz->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(02859) "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(02860) - "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(02861) "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(02862) "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(02863) "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(02864) "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(02865) "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(02866) "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(); @@ -876,9 +764,8 @@ static void child_main(motorz_core_t *mz, int child_num_arg, int child_bucket) ap_sb_handle_t *sbh; 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 */ + mz->mpm->mpm_state = AP_MPMQ_STARTING; my_child_num = child_num_arg; ap_my_pid = getpid(); @@ -898,7 +785,7 @@ static void child_main(motorz_core_t *mz, int child_num_arg, int child_bucket) #endif /* close unused listeners and pods */ - for (i = 0; i < num_buckets; i++) { + for (i = 0; i < mz->mpm->num_buckets; i++) { if (i != child_bucket) { ap_close_listeners_ex(all_buckets[i].listeners); ap_mpm_pod_close(all_buckets[i].pod); @@ -984,12 +871,15 @@ static void child_main(motorz_core_t *mz, int child_num_arg, int child_bucket) lr->accept_func = ap_unixd_accept; } - mpm_state = AP_MPMQ_RUNNING; + mz->mpm->mpm_state = AP_MPMQ_RUNNING; /* 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 + && !mz->mpm->shutdown_pending + && !mz->mpm->restart_pending) { /* * (Re)initialize this child to a pre-connection state. */ @@ -1047,7 +937,7 @@ static void child_main(motorz_core_t *mz, 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 (mz->my_generation != + else if (mz->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? @@ -1070,13 +960,6 @@ static int make_child(motorz_core_t *mz, 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); motorz_note_child_started(mz, slot, getpid()); child_main(mz, slot, 0); /* NOTREACHED */ @@ -1154,7 +1037,7 @@ static void startup_children(motorz_core_t *mz, int number_to_start) if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { continue; } - if (make_child(mz, ap_server_conf, i, i % num_buckets) < 0) { + if (make_child(mz, ap_server_conf, i, i % mz->mpm->num_buckets) < 0) { break; } --number_to_start; @@ -1192,12 +1075,12 @@ static void perform_idle_server_maintenance(motorz_core_t *mz, 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) % mz->mpm->num_buckets; ap_mpm_pod_signal(all_buckets[bucket_kill_child_record].pod); } else if (active < ap_num_kids) { bucket_make_child_record++; - bucket_make_child_record %= num_buckets; + bucket_make_child_record %= mz->mpm->num_buckets; make_child(mz, ap_server_conf, free_slots[0], bucket_make_child_record); } @@ -1216,19 +1099,21 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_log_pid(pconf, ap_pid_fname); - if (!mz->is_graceful) { + if (!mz->mpm->was_graceful) { if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - mpm_state = AP_MPMQ_STOPPING; + mz->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 = mz->my_generation; + ap_scoreboard_image->global->running_generation = mz->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); @@ -1241,8 +1126,8 @@ static int motorz_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_num_kids < num_buckets) - ap_num_kids = num_buckets; + if (ap_num_kids < mz->mpm->num_buckets) + ap_num_kids = mz->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 @@ -1253,7 +1138,7 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * supposed to start up without the 1 second penalty between each fork. */ remaining_children_to_start = ap_num_kids; - if (!mz->is_graceful) { + if (!mz->mpm->was_graceful) { startup_children(mz, remaining_children_to_start); remaining_children_to_start = 0; } @@ -1272,9 +1157,9 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) : "none", apr_proc_mutex_defname()); - mpm_state = AP_MPMQ_RUNNING; + mz->mpm->mpm_state = AP_MPMQ_RUNNING; - while (!restart_pending && !shutdown_pending) { + while (!mz->mpm->restart_pending && !mz->mpm->shutdown_pending) { int child_slot; apr_exit_why_e exitwhy; int status, processed_status; @@ -1298,8 +1183,8 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) */ if (child_slot < 0 || ap_get_scoreboard_process(child_slot)->generation - == mz->my_generation) { - mpm_state = AP_MPMQ_STOPPING; + == mz->mpm->my_generation) { + mz->mpm->mpm_state = AP_MPMQ_STOPPING; return !OK; } else { @@ -1330,7 +1215,7 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) /* handled */ #endif } - else if (mz->is_graceful) { + else if (mz->mpm->was_graceful) { /* Great, we've probably just lost a slot in the * scoreboard. Somehow we don't know about this * child. @@ -1363,9 +1248,9 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) perform_idle_server_maintenance(mz, pconf); } - mpm_state = AP_MPMQ_STOPPING; + mz->mpm->mpm_state = AP_MPMQ_STOPPING; - if (shutdown_pending && !mz->is_graceful) { + if (mz->mpm->shutdown_pending && mz->mpm->is_ungraceful) { /* Time to shut down: * Kill child processes, tell them to call child_exit, etc... */ @@ -1381,7 +1266,9 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) "caught SIGTERM, shutting down"); return DONE; - } else if (shutdown_pending) { + } + + if (mz->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 @@ -1394,7 +1281,7 @@ static int motorz_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 < mz->mpm->num_buckets; i++) { ap_mpm_pod_killpg(all_buckets[i].pod, mz->max_daemons_limit); } @@ -1422,7 +1309,7 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) } /* Don't really exit until each child has finished */ - shutdown_pending = 0; + mz->mpm->shutdown_pending = 0; do { /* Pause for a second */ sleep(1); @@ -1438,7 +1325,7 @@ static int motorz_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) break; } } - } while (!shutdown_pending && active_children && + } while (!mz->mpm->shutdown_pending && active_children && (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff)); /* We might be here because we received SIGTERM, either @@ -1451,8 +1338,6 @@ static int motorz_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; @@ -1462,15 +1347,15 @@ static int motorz_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. */ - ++mz->my_generation; - ap_scoreboard_image->global->running_generation = mz->my_generation; + ++mz->mpm->my_generation; + ap_scoreboard_image->global->running_generation = mz->mpm->my_generation; - if (mz->is_graceful) { + if (!mz->mpm->is_ungraceful) { ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(02882) "Graceful restart requested, doing restart"); /* kill off the idle ones */ - for (i = 0; i < num_buckets; i++) { + for (i = 0; i < mz->mpm->num_buckets; i++) { ap_mpm_pod_killpg(all_buckets[i].pod, mz->max_daemons_limit); } @@ -1523,7 +1408,7 @@ static int motorz_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 (mz->module_loads == 1) { + if (mz->mpm->module_loads == 1) { startup = 1; level_flags |= APLOG_STARTUP; } @@ -1536,22 +1421,22 @@ static int motorz_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, } if (one_process) { - num_buckets = 1; + mz->mpm->num_buckets = 1; } - else if (!mz->is_graceful) { /* Preserve the number of buckets - on graceful restarts. */ - num_buckets = 0; + else if (!mz->mpm->was_graceful) { + /* Preserve the number of buckets on graceful restarts. */ + mz->mpm->num_buckets = 0; } if ((rv = ap_duplicate_listeners(pconf, ap_server_conf, - &listen_buckets, &num_buckets))) { + &listen_buckets, &mz->mpm->num_buckets))) { ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, (startup ? NULL : s), APLOGNO(03276) "could not duplicate listeners"); return !OK; } - all_buckets = apr_pcalloc(pconf, num_buckets * + all_buckets = apr_pcalloc(pconf, mz->mpm->num_buckets * sizeof(motorz_child_bucket)); - for (i = 0; i < num_buckets; i++) { + for (i = 0; i < mz->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), APLOGNO(03277) @@ -1581,8 +1466,6 @@ static int motorz_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) const char *userdata_key = "mpm_motorz_module"; motorz_core_t *mz; - mpm_state = AP_MPMQ_STARTING; - debug = ap_exists_config_define("DEBUG"); if (debug) { @@ -1598,16 +1481,23 @@ static int motorz_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 */ mz = g_motorz_core = ap_retained_data_get(userdata_key); if (!g_motorz_core) { mz = g_motorz_core = ap_retained_data_create(userdata_key, sizeof(*g_motorz_core)); + mz->mpm = ap_unixd_mpm_get_retained_data(); mz->max_daemons_limit = -1; mz->timeout_ring = motorz_timer_ring; mz->pollset = motorz_pollset; } - ++mz->module_loads; - if (mz->module_loads == 2) { + mz->mpm->mpm_state = AP_MPMQ_STARTING; + if (mz->mpm->baton != mz) { + mz->mpm->was_graceful = 0; + mz->mpm->baton = mz; + } + ++mz->mpm->module_loads; + + /* sigh, want this only the second time around */ + if (mz->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); @@ -1645,7 +1535,7 @@ static int motorz_check_config(apr_pool_t *p, apr_pool_t *plog, motorz_core_t *mz = motorz_core_get(); /* the reverse of pre_config, we want this only the first time around */ - if (mz->module_loads == 1) { + if (mz->mpm->module_loads == 1) { startup = 1; } diff --git a/server/mpm/motorz/motorz.h b/server/mpm/motorz/motorz.h index c62222c860..a54357b120 100644 --- a/server/mpm/motorz/motorz.h +++ b/server/mpm/motorz/motorz.h @@ -115,10 +115,9 @@ */ typedef struct motorz_core_t motorz_core_t; struct motorz_core_t { + 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 diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index ec41073134..6649efe7e7 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -94,17 +94,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 @@ -131,7 +129,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 */ @@ -215,14 +212,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; apr_signal(SIGHUP, SIG_IGN); apr_signal(SIGTERM, SIG_IGN); @@ -246,7 +243,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); @@ -265,7 +262,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 @@ -333,10 +330,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; @@ -359,130 +356,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(); @@ -509,9 +394,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(); @@ -537,7 +421,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); @@ -603,14 +487,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; @@ -648,7 +535,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); } @@ -737,7 +625,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? @@ -761,13 +649,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 */ @@ -852,7 +733,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; @@ -913,7 +794,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; } @@ -940,7 +821,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); } @@ -972,19 +853,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); @@ -997,14 +880,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 @@ -1018,7 +901,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; } @@ -1043,9 +926,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; @@ -1069,8 +952,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 { @@ -1107,7 +990,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. @@ -1140,9 +1023,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... */ @@ -1158,7 +1041,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 @@ -1171,7 +1056,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); } @@ -1199,7 +1084,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); @@ -1215,7 +1100,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 @@ -1228,8 +1113,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; @@ -1239,15 +1122,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); } @@ -1299,7 +1182,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; } @@ -1312,22 +1195,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), APLOGNO(03280) "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), APLOGNO(03281) @@ -1356,8 +1239,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) { @@ -1373,15 +1254,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); @@ -1414,7 +1302,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; } diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index e3452c99a3..0de0726bba 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -135,19 +135,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; /* @@ -168,12 +166,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; @@ -314,7 +306,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 @@ -373,10 +365,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; @@ -404,7 +396,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) @@ -437,7 +429,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); } @@ -460,153 +452,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... */ @@ -956,7 +801,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); @@ -1262,15 +1107,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); @@ -1353,7 +1198,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. */ @@ -1439,7 +1284,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 */ @@ -1510,7 +1354,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; @@ -1576,7 +1420,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; } @@ -1630,7 +1474,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) @@ -1726,7 +1570,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) { @@ -1740,8 +1584,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; } @@ -1787,7 +1631,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; @@ -1800,7 +1644,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. */ @@ -1838,25 +1682,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... @@ -1889,7 +1735,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; } @@ -1912,12 +1758,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... */ @@ -1935,7 +1781,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... */ @@ -1966,7 +1814,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)); @@ -1982,7 +1830,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 @@ -1999,8 +1847,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; @@ -2010,10 +1856,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 */ @@ -2062,7 +1908,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; } @@ -2077,9 +1923,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))) { @@ -2111,25 +1957,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]; } @@ -2138,7 +1984,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; } @@ -2150,8 +1996,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) { @@ -2166,14 +2010,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); @@ -2210,7 +2061,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; } diff --git a/server/mpm_unix.c b/server/mpm_unix.c index cd3bc52d51..fb589fda2f 100644 --- a/server/mpm_unix.c +++ b/server/mpm_unix.c @@ -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; |