diff options
author | Yann Ylavic <ylavic@apache.org> | 2021-08-24 22:22:40 +0000 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2021-08-24 22:22:40 +0000 |
commit | 243c5fad0a8da9a1008681ac60f5b981de6c18d6 (patch) | |
tree | c1ab175d1fdfac1dfbeca0b3ce5e5dc5e50d77ee | |
parent | 9acfea84831efac669e2cd4cae519e0cae7e947f (diff) | |
download | httpd-243c5fad0a8da9a1008681ac60f5b981de6c18d6.tar.gz |
mpm_{event,worker,prefork}: late stop of children processes on restart.
Change how the main process handles restarts, from:
0. <restart signal>
1. stop old generation of children processes (graceful or not)
2. reload new configuration
3. start new generation of children processes
to:
0. <restart signal>
1. reload new configuration
2. stop old generation of children processes (graceful or not)
3. start new generation of children processes
The delay between stop and start is now very short and does not depend on the
reload time (which can be quite long with many vhosts and/or complex setups
with regexps or whatever third party components to compile).
Also, while reloading, the old generation of children processes keeps accepting
and handling incoming connections until the new generation is up to take over.
* os/unix/unixd.c (sig_term, sig_restart):
Set AP_MPMQ_STOPPING only once.
* server/listen.c (ap_duplicate_listeners):
Use ap_log_error() the main server instead of ap_log_perror().
* server/mpm/{event,worker,prefork}/{event,worker,prefork}.c
({event,worker,prefork}_retained_data):
Save the generation pool pointer (gen_pool) and all the buckets here, they
won't be cleared before the reload like pconf so they need a persitent
storage accross restarts (i.e. retained->gen_pool).
* server/mpm/{event,worker,prefork}/{event,worker,prefork}.c
(perform_idle_server_maintenance, child_main, make_child):
Change usage of all_buckets (previously with global/static scope) to the new
retained->buckets array.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1892587 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | os/unix/unixd.c | 4 | ||||
-rw-r--r-- | server/listen.c | 4 | ||||
-rw-r--r-- | server/mpm/event/event.c | 249 | ||||
-rw-r--r-- | server/mpm/prefork/prefork.c | 257 | ||||
-rw-r--r-- | server/mpm/worker/worker.c | 270 |
5 files changed, 404 insertions, 380 deletions
diff --git a/os/unix/unixd.c b/os/unix/unixd.c index 3b0e695727..eed76f683b 100644 --- a/os/unix/unixd.c +++ b/os/unix/unixd.c @@ -469,7 +469,6 @@ static void sig_term(int sig) /* Main process (ap_pglobal) is dying */ return; } - retained_data->mpm_state = AP_MPMQ_STOPPING; if (retained_data->shutdown_pending && (retained_data->is_ungraceful || sig == AP_SIG_GRACEFUL_STOP)) { @@ -477,6 +476,7 @@ static void sig_term(int sig) return; } + retained_data->mpm_state = AP_MPMQ_STOPPING; retained_data->shutdown_pending = 1; if (sig != AP_SIG_GRACEFUL_STOP) { retained_data->is_ungraceful = 1; @@ -489,7 +489,6 @@ static void sig_restart(int sig) /* Main process (ap_pglobal) is dying */ return; } - retained_data->mpm_state = AP_MPMQ_STOPPING; if (retained_data->restart_pending && (retained_data->is_ungraceful || sig == AP_SIG_GRACEFUL)) { @@ -497,6 +496,7 @@ static void sig_restart(int sig) return; } + retained_data->mpm_state = AP_MPMQ_STOPPING; retained_data->restart_pending = 1; if (sig != AP_SIG_GRACEFUL) { retained_data->is_ungraceful = 1; diff --git a/server/listen.c b/server/listen.c index 445d1202c9..812bdd8bb3 100644 --- a/server/listen.c +++ b/server/listen.c @@ -853,7 +853,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, if (val > 1) { *num_buckets = val; } - ap_log_perror(APLOG_MARK, APLOG_INFO, 0, p, APLOGNO(02819) + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02819) "Using %i listeners bucket(s) based on %i " "online CPU cores and a ratio of %i", *num_buckets, num_online_cores, @@ -862,7 +862,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, else #endif if (!warn_once) { - ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p, APLOGNO(02820) + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02820) "ListenCoresBucketsRatio ignored without " "SO_REUSEPORT and _SC_NPROCESSORS_ONLN " "support: using a single listeners bucket"); diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 1a27a8fc57..dca98d4c3d 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -392,6 +392,12 @@ typedef struct socket_callback_baton unsigned int signaled :1; } socket_callback_baton_t; +typedef struct event_child_bucket { + ap_pod_t *pod; + ap_listen_rec *listeners; +} event_child_bucket; +static event_child_bucket *my_bucket; /* Current child bucket */ + /* data retained by event across load/unload of the module * allocated on first call to pre-config hook; located on * subsequent calls to pre-config hook @@ -399,6 +405,9 @@ typedef struct socket_callback_baton typedef struct event_retained_data { ap_unixd_mpm_retained_data *mpm; + apr_pool_t *gen_pool; /* generation pool (children start->stop lifetime) */ + event_child_bucket *buckets; /* children buckets (reset per generation) */ + int first_server_limit; int first_thread_limit; int sick_child_detected; @@ -433,13 +442,6 @@ typedef struct event_retained_data { } event_retained_data; static event_retained_data *retained; -typedef struct event_child_bucket { - ap_pod_t *pod; - ap_listen_rec *listeners; -} event_child_bucket; -static event_child_bucket *all_buckets, /* All listeners buckets */ - *my_bucket; /* Current child bucket */ - struct event_srv_cfg_s { struct timeout_queue *wc_q, *ka_q; @@ -2833,8 +2835,8 @@ static void child_main(int child_num_arg, int child_bucket) /* close unused listeners and pods */ 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); + ap_close_listeners_ex(retained->buckets[i].listeners); + ap_mpm_podx_close(retained->buckets[i].pod); } } @@ -2859,6 +2861,9 @@ static void child_main(int child_num_arg, int child_bucket) clean_child_exit(APEXIT_CHILDFATAL); } + /* For rand() users (e.g. skiplist). */ + srand((unsigned int)apr_time_now()); + ap_run_child_init(pchild, ap_server_conf); if (ap_max_requests_per_child) { @@ -3009,7 +3014,7 @@ static int make_child(server_rec * s, int slot, int bucket) } if (one_process) { - my_bucket = &all_buckets[0]; + my_bucket = &retained->buckets[0]; event_note_child_started(slot, getpid()); child_main(slot, 0); @@ -3038,7 +3043,7 @@ static int make_child(server_rec * s, int slot, int bucket) } if (!pid) { - my_bucket = &all_buckets[bucket]; + my_bucket = &retained->buckets[bucket]; #ifdef HAVE_BINDPROCESSOR /* By default, AIX binds to a single processor. This bit unbinds @@ -3188,7 +3193,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) if (retained->total_daemons <= active_daemons_limit && retained->total_daemons < server_limit) { /* Kill off one child */ - ap_mpm_podx_signal(all_buckets[child_bucket].pod, + ap_mpm_podx_signal(retained->buckets[child_bucket].pod, AP_MPM_PODX_GRACEFUL); retained->idle_spawn_rate[child_bucket] = 1; active_daemons--; @@ -3385,25 +3390,122 @@ 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) { + ap_listen_rec **listen_buckets = NULL; int num_buckets = retained->mpm->num_buckets; int remaining_children_to_start; + apr_status_t rv; int i; ap_log_pid(pconf, ap_pid_fname); + /* On first startup create gen_pool to satisfy the lifetime of the + * parent's PODs and listeners; on restart stop the children from the + * previous generation and clear gen_pool for the next one. + */ + if (!retained->gen_pool) { + apr_pool_create(&retained->gen_pool, ap_pglobal); + } + else { + if (retained->mpm->was_graceful) { + /* wake up the children...time to die. But we'll have more soon */ + for (i = 0; i < num_buckets; i++) { + ap_mpm_podx_killpg(retained->buckets[i].pod, + active_daemons_limit, AP_MPM_PODX_GRACEFUL); + } + } + else { + /* Kill 'em all. Since the child acts the same on the parents SIGTERM + * and a SIGHUP, we may as well use the same signal, because some user + * pthreads are stealing signals from us left and right. + */ + for (i = 0; i < num_buckets; i++) { + ap_mpm_podx_killpg(retained->buckets[i].pod, + active_daemons_limit, AP_MPM_PODX_RESTART); + } + ap_reclaim_child_processes(1, /* Start with SIGTERM */ + event_note_child_killed); + } + apr_pool_clear(retained->gen_pool); + retained->buckets = NULL; + + /* advance to the next generation */ + /* XXX: we really need to make sure this new generation number isn't in + * use by any of the previous children. + */ + ++retained->mpm->my_generation; + } + + /* On graceful restart, preserve the scoreboard and the listeners buckets. + * When ungraceful, clear the scoreboard and set num_buckets to zero to let + * ap_duplicate_listeners() below determine how many are needed/configured. + */ if (!retained->mpm->was_graceful) { if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { 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->mpm->my_generation; + num_buckets = (one_process) ? 1 : 0; /* one_process => one bucket */ + retained->mpm->num_buckets = 0; /* reset idle_spawn_rate below */ } + /* Now on for the new generation. */ + ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; ap_unixd_mpm_set_signals(pconf, one_process); + if ((rv = ap_duplicate_listeners(retained->gen_pool, ap_server_conf, + &listen_buckets, &num_buckets))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03273) + "could not duplicate listeners"); + return !OK; + } + + retained->buckets = apr_pcalloc(retained->gen_pool, + num_buckets * sizeof(event_child_bucket)); + for (i = 0; i < num_buckets; i++) { + if (!one_process /* no POD in one_process mode */ + && (rv = ap_mpm_podx_open(retained->gen_pool, + &retained->buckets[i].pod))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03274) + "could not open pipe-of-death"); + return !OK; + } + retained->buckets[i].listeners = listen_buckets[i]; + } + + if (retained->mpm->max_buckets < num_buckets) { + int new_max, *new_ptr; + 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)); + if (retained->mpm->num_buckets) /* idle_spawn_rate NULL at startup */ + memcpy(new_ptr, retained->idle_spawn_rate, + retained->mpm->num_buckets * sizeof(int)); + retained->idle_spawn_rate = new_ptr; + retained->mpm->max_buckets = new_max; + } + 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->mpm->num_buckets; i++) { + if (rate_max < retained->idle_spawn_rate[i]) { + rate_max = retained->idle_spawn_rate[i]; + } + } + for (/* up to date i */; i < num_buckets; i++) { + retained->idle_spawn_rate[i] = rate_max; + } + } + retained->mpm->num_buckets = num_buckets; + + active_daemons = 0; + /* Don't thrash since num_buckets depends on the * system and the number of online CPU cores... */ @@ -3463,8 +3565,8 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) * Kill child processes, tell them to call child_exit, etc... */ for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, - AP_MPM_PODX_RESTART); + ap_mpm_podx_killpg(retained->buckets[i].pod, + active_daemons_limit, AP_MPM_PODX_RESTART); } ap_reclaim_child_processes(1, /* Start with SIGTERM */ event_note_child_killed); @@ -3490,8 +3592,8 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) /* Close our listeners, and then ask our children to do same */ ap_close_listeners(); for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, - AP_MPM_PODX_GRACEFUL); + ap_mpm_podx_killpg(retained->buckets[i].pod, + active_daemons_limit, AP_MPM_PODX_GRACEFUL); } ap_relieve_child_processes(event_note_child_killed); @@ -3533,8 +3635,8 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) * really dead. */ for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, - AP_MPM_PODX_RESTART); + ap_mpm_podx_killpg(retained->buckets[i].pod, + active_daemons_limit, AP_MPM_PODX_RESTART); } ap_reclaim_child_processes(1, event_note_child_killed); @@ -3547,46 +3649,15 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) return DONE; } - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++retained->mpm->my_generation; - ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; - 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"); - /* wake up the children...time to die. But we'll have more soon */ - for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, - AP_MPM_PODX_GRACEFUL); - } - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - + "%s received. Doing graceful restart", + AP_SIG_GRACEFUL_STRING); } else { - /* Kill 'em all. Since the child acts the same on the parents SIGTERM - * and a SIGHUP, we may as well use the same signal, because some user - * pthreads are stealing signals from us left and right. - */ - for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, - AP_MPM_PODX_RESTART); - } - - ap_reclaim_child_processes(1, /* Start with SIGTERM */ - event_note_child_killed); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00494) "SIGHUP received. Attempting to restart"); } - - active_daemons = 0; - return OK; } @@ -3647,10 +3718,6 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, { int startup = 0; int level_flags = 0; - int num_buckets = 0; - ap_listen_rec **listen_buckets; - apr_status_t rv; - int i; pconf = p; @@ -3667,65 +3734,6 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, return !OK; } - if (one_process) { - num_buckets = 1; - } - else if (retained->mpm->was_graceful) { - /* Preserve the number of buckets on graceful restarts. */ - num_buckets = retained->mpm->num_buckets; - } - if ((rv = ap_duplicate_listeners(pconf, ap_server_conf, - &listen_buckets, &num_buckets))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, - (startup ? NULL : s), APLOGNO(03273) - "could not duplicate listeners"); - return !OK; - } - - all_buckets = apr_pcalloc(pconf, num_buckets * sizeof(*all_buckets)); - for (i = 0; i < num_buckets; i++) { - if (!one_process && /* no POD in one_process mode */ - (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, - (startup ? NULL : s), APLOGNO(03274) - "could not open pipe-of-death"); - return !OK; - } - all_buckets[i].listeners = listen_buckets[i]; - } - - if (retained->mpm->max_buckets < num_buckets) { - int new_max, *new_ptr; - 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)); - if (retained->idle_spawn_rate) /* NULL at startup */ - memcpy(new_ptr, retained->idle_spawn_rate, - retained->mpm->num_buckets * sizeof(int)); - retained->idle_spawn_rate = new_ptr; - retained->mpm->max_buckets = new_max; - } - 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->mpm->num_buckets; i++) { - if (rate_max < retained->idle_spawn_rate[i]) { - rate_max = retained->idle_spawn_rate[i]; - } - } - for (/* up to date i */; i < num_buckets; i++) { - retained->idle_spawn_rate[i] = rate_max; - } - } - retained->mpm->num_buckets = num_buckets; - - /* for skiplist */ - srand((unsigned int)apr_time_now()); return OK; } @@ -3753,16 +3761,13 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog, if (!retained) { retained = ap_retained_data_create(userdata_key, sizeof(*retained)); retained->mpm = ap_unixd_mpm_get_retained_data(); + retained->mpm->baton = retained; 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->mpm->module_loads; /* test once for correct operation of fdqueue */ diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 447b901ed8..5b33b7fb82 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -95,6 +95,13 @@ static int ap_daemons_max_free=0; static int ap_daemons_limit=0; /* MaxRequestWorkers */ static int server_limit = 0; +typedef struct prefork_child_bucket { + ap_pod_t *pod; + ap_listen_rec *listeners; + apr_proc_mutex_t *mutex; +} prefork_child_bucket; +static prefork_child_bucket *my_bucket; /* Current child bucket */ + /* 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 @@ -102,6 +109,9 @@ static int server_limit = 0; typedef struct prefork_retained_data { ap_unixd_mpm_retained_data *mpm; + apr_pool_t *gen_pool; /* generation pool (children start->stop lifetime) */ + prefork_child_bucket *buckets; /* children buckets (reset per generation) */ + int first_server_limit; int maxclients_reported; /* @@ -124,14 +134,6 @@ typedef struct prefork_retained_data { } prefork_retained_data; static prefork_retained_data *retained; -typedef struct prefork_child_bucket { - ap_pod_t *pod; - ap_listen_rec *listeners; - apr_proc_mutex_t *mutex; -} prefork_child_bucket; -static prefork_child_bucket *all_buckets, /* All listeners buckets */ - *my_bucket; /* Current child bucket */ - #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) /* one_process --- debugging mode variable; can be set from the command line @@ -443,8 +445,8 @@ static void child_main(int child_num_arg, int child_bucket) /* close unused listeners and pods */ 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); + ap_close_listeners_ex(retained->buckets[i].listeners); + ap_mpm_pod_close(retained->buckets[i].pod); } } @@ -696,7 +698,7 @@ static int make_child(server_rec *s, int slot) } if (one_process) { - my_bucket = &all_buckets[0]; + my_bucket = &retained->buckets[0]; prefork_note_child_started(slot, getpid()); child_main(slot, 0); @@ -732,7 +734,7 @@ static int make_child(server_rec *s, int slot) } if (!pid) { - my_bucket = &all_buckets[bucket]; + my_bucket = &retained->buckets[bucket]; #ifdef HAVE_BINDPROCESSOR /* by default AIX binds to a single processor @@ -842,7 +844,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p) * while we were counting */ bucket_kill_child_record = (bucket_kill_child_record + 1) % retained->mpm->num_buckets; - ap_mpm_pod_signal(all_buckets[bucket_kill_child_record].pod); + ap_mpm_pod_signal(retained->buckets[bucket_kill_child_record].pod); retained->idle_spawn_rate = 1; } else if (idle_count < ap_daemons_min_free) { @@ -891,44 +893,127 @@ static void perform_idle_server_maintenance(apr_pool_t *p) static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) { - int index; + ap_listen_rec **listen_buckets = NULL; + int num_buckets = retained->mpm->num_buckets; int remaining_children_to_start; + apr_status_t rv; + char id[16]; int i; ap_log_pid(pconf, ap_pid_fname); + /* On first startup create gen_pool to satisfy the lifetime of the + * parent's PODs and listeners; on restart stop the children from the + * previous generation and clear gen_pool for the next one. + */ + if (!retained->gen_pool) { + apr_pool_create(&retained->gen_pool, ap_pglobal); + } + else { + if (retained->mpm->was_graceful) { + /* kill off the idle ones */ + for (i = 0; i < num_buckets; i++) { + ap_mpm_pod_killpg(retained->buckets[i].pod, + retained->max_daemons_limit); + } + + /* This is mostly for debugging... so that we know what is still + * gracefully dealing with existing request. This will break + * in a very nasty way if we ever have the scoreboard totally + * file-based (no shared memory) + */ + for (i = 0; i < ap_daemons_limit; ++i) { + if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { + ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL; + /* Ask each child to close its listeners. + * + * NOTE: we use the scoreboard, because if we send SIGUSR1 + * to every process in the group, this may include CGI's, + * piped loggers, etc. They almost certainly won't handle + * it gracefully. + */ + ap_mpm_safe_kill(ap_scoreboard_image->parent[i].pid, + AP_SIG_GRACEFUL); + } + } + } + else { + /* Kill 'em off */ + if (ap_unixd_killpg(getpgrp(), SIGHUP) < 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, + ap_server_conf, APLOGNO(00172) "killpg SIGHUP"); + } + ap_reclaim_child_processes(0, /* Not when just starting up */ + prefork_note_child_killed); + } + apr_pool_clear(retained->gen_pool); + retained->buckets = NULL; + + /* advance to the next generation */ + /* XXX: we really need to make sure this new generation number isn't in + * use by any of the children. + */ + ++retained->mpm->my_generation; + } + if (!retained->mpm->was_graceful) { if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { 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->mpm->my_generation; + num_buckets = (one_process) ? 1 : 0; /* one_process => one bucket */ + retained->idle_spawn_rate = 1; /* reset idle_spawn_rate */ } + /* Now on for the new generation. */ + ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; ap_unixd_mpm_set_signals(pconf, one_process); - if (one_process) { - AP_MONCONTROL(1); - make_child(ap_server_conf, 0); - /* NOTREACHED */ - ap_assert(0); + if ((rv = ap_duplicate_listeners(retained->gen_pool, ap_server_conf, + &listen_buckets, &num_buckets))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03280) + "could not duplicate listeners"); return !OK; } + retained->buckets = apr_pcalloc(retained->gen_pool, + num_buckets * sizeof(*retained->buckets)); + for (i = 0; i < num_buckets; i++) { + if (!one_process /* no POD in one_process mode */ + && (rv = ap_mpm_pod_open(retained->gen_pool, + &retained->buckets[i].pod))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03281) + "could not open pipe-of-death"); + return !OK; + } + /* Initialize cross-process accept lock (safe accept needed only) */ + if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i), + ap_proc_mutex_create(&retained->buckets[i].mutex, + NULL, AP_ACCEPT_MUTEX_TYPE, + id, s, retained->gen_pool, + 0))))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03282) + "could not create accept mutex"); + return !OK; + } + retained->buckets[i].listeners = listen_buckets[i]; + } + retained->mpm->num_buckets = num_buckets; + /* Don't thrash since num_buckets depends on the * system and the number of online CPU cores... */ - 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 (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 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 @@ -962,13 +1047,21 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_log_mpm_common(s); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00165) "Accept mutex: %s (default: %s)", - (all_buckets[0].mutex) - ? apr_proc_mutex_name(all_buckets[0].mutex) + (retained->buckets[0].mutex) + ? apr_proc_mutex_name(retained->buckets[0].mutex) : "none", apr_proc_mutex_defname()); retained->mpm->mpm_state = AP_MPMQ_RUNNING; + if (one_process) { + AP_MONCONTROL(1); + make_child(ap_server_conf, 0); + /* NOTREACHED */ + ap_assert(0); + return !OK; + } + while (!retained->mpm->restart_pending && !retained->mpm->shutdown_pending) { int child_slot; apr_exit_why_e exitwhy; @@ -1096,16 +1189,17 @@ 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 < retained->mpm->num_buckets; i++) { - ap_mpm_pod_killpg(all_buckets[i].pod, retained->max_daemons_limit); + for (i = 0; i < num_buckets; i++) { + ap_mpm_pod_killpg(retained->buckets[i].pod, + retained->max_daemons_limit); } /* Send SIGUSR1 to the active children */ active_children = 0; - for (index = 0; index < ap_daemons_limit; ++index) { - if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { + for (i = 0; i < ap_daemons_limit; ++i) { + if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { /* Ask each child to close its listeners. */ - ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL); + ap_mpm_safe_kill(MPM_CHILD_PID(i), AP_SIG_GRACEFUL); active_children++; } } @@ -1133,8 +1227,8 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_relieve_child_processes(prefork_note_child_killed); active_children = 0; - for (index = 0; index < ap_daemons_limit; ++index) { - if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { + for (i = 0; i < ap_daemons_limit; ++i) { + if (ap_mpm_safe_kill(MPM_CHILD_PID(i), 0) == APR_SUCCESS) { active_children = 1; /* Having just one child is enough to stay around */ break; @@ -1158,52 +1252,14 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) return DONE; } - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++retained->mpm->my_generation; - ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; - 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 < retained->mpm->num_buckets; i++) { - ap_mpm_pod_killpg(all_buckets[i].pod, retained->max_daemons_limit); - } - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. This will break - * in a very nasty way if we ever have the scoreboard totally - * file-based (no shared memory) - */ - for (index = 0; index < ap_daemons_limit; ++index) { - if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { - ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL; - /* Ask each child to close its listeners. - * - * NOTE: we use the scoreboard, because if we send SIGUSR1 - * to every process in the group, this may include CGI's, - * piped loggers, etc. They almost certainly won't handle - * it gracefully. - */ - ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL); - } - } } else { - /* Kill 'em off */ - if (ap_unixd_killpg(getpgrp(), SIGHUP) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00172) "killpg SIGHUP"); - } - ap_reclaim_child_processes(0, /* Not when just starting up */ - prefork_note_child_killed); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00173) "SIGHUP received. Attempting to restart"); } - return OK; } @@ -1214,10 +1270,6 @@ static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, { int startup = 0; int level_flags = 0; - ap_listen_rec **listen_buckets; - apr_status_t rv; - char id[16]; - int i; pconf = p; @@ -1234,42 +1286,6 @@ static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, return !OK; } - if (one_process) { - retained->mpm->num_buckets = 1; - } - 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, &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, retained->mpm->num_buckets * - sizeof(prefork_child_bucket)); - 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) - "could not open pipe-of-death"); - return !OK; - } - /* Initialize cross-process accept lock (safe accept needed only) */ - if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i), - ap_proc_mutex_create(&all_buckets[i].mutex, - NULL, AP_ACCEPT_MUTEX_TYPE, - id, s, pconf, 0))))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, - (startup ? NULL : s), APLOGNO(03282) - "could not create accept mutex"); - return !OK; - } - all_buckets[i].listeners = listen_buckets[i]; - } - return OK; } @@ -1298,14 +1314,11 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp if (!retained) { retained = ap_retained_data_create(userdata_key, sizeof(*retained)); retained->mpm = ap_unixd_mpm_get_retained_data(); + retained->mpm->baton = retained; retained->max_daemons_limit = -1; retained->idle_spawn_rate = 1; } 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 */ diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index cf1837239e..1f370b2a3b 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -137,6 +137,12 @@ static fd_queue_t *worker_queue; static fd_queue_info_t *worker_queue_info; static apr_pollset_t *worker_pollset; +typedef struct worker_child_bucket { + ap_pod_t *pod; + ap_listen_rec *listeners; + apr_proc_mutex_t *mutex; +} worker_child_bucket; +static worker_child_bucket *my_bucket; /* Current child bucket */ /* data retained by worker across load/unload of the module * allocated on first call to pre-config hook; located on @@ -145,6 +151,9 @@ static apr_pollset_t *worker_pollset; typedef struct worker_retained_data { ap_unixd_mpm_retained_data *mpm; + apr_pool_t *gen_pool; /* generation pool (children start->stop lifetime) */ + worker_child_bucket *buckets; /* children buckets (reset per generation) */ + int first_server_limit; int first_thread_limit; int sick_child_detected; @@ -171,14 +180,6 @@ typedef struct worker_retained_data { } worker_retained_data; static worker_retained_data *retained; -typedef struct worker_child_bucket { - ap_pod_t *pod; - ap_listen_rec *listeners; - apr_proc_mutex_t *mutex; -} worker_child_bucket; -static worker_child_bucket *all_buckets, /* All listeners buckets */ - *my_bucket; /* Current child bucket */ - #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) /* The structure used to pass unique initialization info to each thread */ @@ -1123,8 +1124,8 @@ static void child_main(int child_num_arg, int child_bucket) /* close unused listeners and pods */ 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); + ap_close_listeners_ex(retained->buckets[i].listeners); + ap_mpm_podx_close(retained->buckets[i].pod); } } @@ -1292,7 +1293,7 @@ static int make_child(server_rec *s, int slot, int bucket) } if (one_process) { - my_bucket = &all_buckets[0]; + my_bucket = &retained->buckets[0]; worker_note_child_started(slot, getpid()); child_main(slot, 0); @@ -1320,7 +1321,7 @@ static int make_child(server_rec *s, int slot, int bucket) } if (!pid) { - my_bucket = &all_buckets[bucket]; + my_bucket = &retained->buckets[bucket]; #ifdef HAVE_BINDPROCESSOR /* By default, AIX binds to a single processor. This bit unbinds @@ -1501,7 +1502,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) if (idle_thread_count > max_spare_threads / num_buckets) { /* Kill off one child */ - ap_mpm_podx_signal(all_buckets[child_bucket].pod, + ap_mpm_podx_signal(retained->buckets[child_bucket].pod, AP_MPM_PODX_GRACEFUL); retained->idle_spawn_rate[child_bucket] = 1; } @@ -1694,25 +1695,133 @@ 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) { + ap_listen_rec **listen_buckets = NULL; int num_buckets = retained->mpm->num_buckets; int remaining_children_to_start; + apr_status_t rv; + char id[16]; int i; ap_log_pid(pconf, ap_pid_fname); + /* On first startup create gen_pool to satisfy the lifetime of the + * parent's PODs, accept mutexes and listeners; on restart stop the + * children from the previous generation and clear gen_pool for the + * next one. + */ + if (!retained->gen_pool) { + apr_pool_create(&retained->gen_pool, ap_pglobal); + } + else { + if (retained->mpm->was_graceful) { + /* wake up the children...time to die. But we'll have more soon */ + for (i = 0; i < num_buckets; i++) { + ap_mpm_podx_killpg(retained->buckets[i].pod, + ap_daemons_limit, AP_MPM_PODX_GRACEFUL); + } + } + else { + /* Kill 'em all. Since the child acts the same on the parents SIGTERM + * and a SIGHUP, we may as well use the same signal, because some user + * pthreads are stealing signals from us left and right. + */ + for (i = 0; i < num_buckets; i++) { + ap_mpm_podx_killpg(retained->buckets[i].pod, + ap_daemons_limit, AP_MPM_PODX_RESTART); + } + ap_reclaim_child_processes(1, /* Start with SIGTERM */ + worker_note_child_killed); + } + apr_pool_clear(retained->gen_pool); + retained->buckets = NULL; + + /* advance to the next generation */ + /* XXX: we really need to make sure this new generation number isn't in + * use by any of the previous children. + */ + ++retained->mpm->my_generation; + } + + /* On graceful restart, preserve the scoreboard and the listeners buckets. + * When ungraceful, clear the scoreboard and set num_buckets to zero to let + * ap_duplicate_listeners() below determine how many are needed/configured. + */ if (!retained->mpm->was_graceful) { if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { 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->mpm->my_generation; + num_buckets = (one_process) ? 1 : 0; /* one_process => one bucket */ + retained->mpm->num_buckets = 0; /* reset idle_spawn_rate below */ } + /* Now on for the new generation. */ + ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; ap_unixd_mpm_set_signals(pconf, one_process); + if ((rv = ap_duplicate_listeners(retained->gen_pool, ap_server_conf, + &listen_buckets, &num_buckets))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03291) + "could not duplicate listeners"); + return !OK; + } + + retained->buckets = apr_pcalloc(retained->gen_pool, + num_buckets * sizeof(*retained->buckets)); + for (i = 0; i < num_buckets; i++) { + if (!one_process /* no POD in one_process mode */ + && (rv = ap_mpm_podx_open(retained->gen_pool, + &retained->buckets[i].pod))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03292) + "could not open pipe-of-death"); + return !OK; + } + /* Initialize cross-process accept lock (safe accept needed only) */ + if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i), + ap_proc_mutex_create(&retained->buckets[i].mutex, + NULL, AP_ACCEPT_MUTEX_TYPE, + id, s, retained->gen_pool, + 0))))) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, + ap_server_conf, APLOGNO(03293) + "could not create accept mutex"); + return !OK; + } + retained->buckets[i].listeners = listen_buckets[i]; + } + + if (retained->mpm->max_buckets < num_buckets) { + int new_max, *new_ptr; + 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)); + if (retained->mpm->num_buckets) /* idle_spawn_rate NULL at startup */ + memcpy(new_ptr, retained->idle_spawn_rate, + retained->mpm->num_buckets * sizeof(int)); + retained->idle_spawn_rate = new_ptr; + retained->mpm->max_buckets = new_max; + } + 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->mpm->num_buckets; i++) { + if (rate_max < retained->idle_spawn_rate[i]) { + rate_max = retained->idle_spawn_rate[i]; + } + } + for (/* up to date i */; i < num_buckets; i++) { + retained->idle_spawn_rate[i] = rate_max; + } + } + retained->mpm->num_buckets = num_buckets; + /* Don't thrash since num_buckets depends on the * system and the number of online CPU cores... */ @@ -1763,8 +1872,8 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_log_mpm_common(s); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00294) "Accept mutex: %s (default: %s)", - (all_buckets[0].mutex) - ? apr_proc_mutex_name(all_buckets[0].mutex) + (retained->buckets[0].mutex) + ? apr_proc_mutex_name(retained->buckets[0].mutex) : "none", apr_proc_mutex_defname()); retained->mpm->mpm_state = AP_MPMQ_RUNNING; @@ -1777,8 +1886,8 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * Kill child processes, tell them to call child_exit, etc... */ for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit, - AP_MPM_PODX_RESTART); + ap_mpm_podx_killpg(retained->buckets[i].pod, + ap_daemons_limit, AP_MPM_PODX_RESTART); } ap_reclaim_child_processes(1, /* Start with SIGTERM */ worker_note_child_killed); @@ -1804,8 +1913,8 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_close_listeners(); for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit, - AP_MPM_PODX_GRACEFUL); + ap_mpm_podx_killpg(retained->buckets[i].pod, + ap_daemons_limit, AP_MPM_PODX_GRACEFUL); } ap_relieve_child_processes(worker_note_child_killed); @@ -1847,8 +1956,8 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * really dead. */ for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit, - AP_MPM_PODX_RESTART); + ap_mpm_podx_killpg(retained->buckets[i].pod, + ap_daemons_limit, AP_MPM_PODX_RESTART); } ap_reclaim_child_processes(1, worker_note_child_killed); @@ -1861,43 +1970,15 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) return DONE; } - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++retained->mpm->my_generation; - ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; - 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 */ - for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit, - AP_MPM_PODX_GRACEFUL); - } - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - + "%s received. Doing graceful restart", + AP_SIG_GRACEFUL_STRING); } else { - /* Kill 'em all. Since the child acts the same on the parents SIGTERM - * and a SIGHUP, we may as well use the same signal, because some user - * pthreads are stealing signals from us left and right. - */ - for (i = 0; i < num_buckets; i++) { - ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit, - AP_MPM_PODX_RESTART); - } - - ap_reclaim_child_processes(1, /* Start with SIGTERM */ - worker_note_child_killed); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00298) - "SIGHUP received. Attempting to restart"); + "SIGHUP received. Attempting to restart"); } - return OK; } @@ -1908,11 +1989,6 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, { int startup = 0; int level_flags = 0; - int num_buckets = 0; - ap_listen_rec **listen_buckets; - apr_status_t rv; - char id[16]; - int i; pconf = p; @@ -1929,73 +2005,6 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, return !OK; } - if (one_process) { - num_buckets = 1; - } - else if (retained->mpm->was_graceful) { - /* Preserve the number of buckets on graceful restarts. */ - num_buckets = retained->mpm->num_buckets; - } - if ((rv = ap_duplicate_listeners(pconf, ap_server_conf, - &listen_buckets, &num_buckets))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, - (startup ? NULL : s), APLOGNO(03291) - "could not duplicate listeners"); - return !OK; - } - - all_buckets = apr_pcalloc(pconf, num_buckets * sizeof(*all_buckets)); - for (i = 0; i < num_buckets; i++) { - if (!one_process && /* no POD in one_process mode */ - (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, - (startup ? NULL : s), APLOGNO(03292) - "could not open pipe-of-death"); - return !OK; - } - /* Initialize cross-process accept lock (safe accept needed only) */ - if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i), - ap_proc_mutex_create(&all_buckets[i].mutex, - NULL, AP_ACCEPT_MUTEX_TYPE, - id, s, pconf, 0))))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, - (startup ? NULL : s), APLOGNO(03293) - "could not create accept mutex"); - return !OK; - } - all_buckets[i].listeners = listen_buckets[i]; - } - - if (retained->mpm->max_buckets < num_buckets) { - int new_max, *new_ptr; - 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)); - if (retained->idle_spawn_rate) /* NULL at startup */ - memcpy(new_ptr, retained->idle_spawn_rate, - retained->mpm->num_buckets * sizeof(int)); - retained->idle_spawn_rate = new_ptr; - retained->mpm->max_buckets = new_max; - } - 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->mpm->num_buckets; i++) { - if (rate_max < retained->idle_spawn_rate[i]) { - rate_max = retained->idle_spawn_rate[i]; - } - } - for (/* up to date i */; i < num_buckets; i++) { - retained->idle_spawn_rate[i] = rate_max; - } - } - retained->mpm->num_buckets = num_buckets; - return OK; } @@ -2024,13 +2033,10 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, if (!retained) { retained = ap_retained_data_create(userdata_key, sizeof(*retained)); retained->mpm = ap_unixd_mpm_get_retained_data(); + retained->mpm->baton = retained; retained->max_daemons_limit = -1; } 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 */ |