summaryrefslogtreecommitdiff
path: root/server/mpm/prefork/prefork.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/mpm/prefork/prefork.c')
-rw-r--r--server/mpm/prefork/prefork.c257
1 files changed, 135 insertions, 122 deletions
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 */