#include "scoreboard.h"
#include "fdqueue.h"
#include "mpm_default.h"
+#include "util_mutex.h"
#include "unixd.h"
#include <signal.h>
static fd_queue_t *worker_queue;
static fd_queue_info_t *worker_queue_info;
static int mpm_state = AP_MPMQ_STARTING;
-static int sick_child_detected;
-static ap_generation_t volatile my_generation = 0;
/* data retained by worker across load/unload of the module
* allocated on first call to pre-config hook; located on
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;
+ /*
+ * The max child slot ever assigned, preserved across restarts. Necessary
+ * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
+ * use this value to optimize routines that have to scan the entire
+ * scoreboard.
+ */
+ int max_daemons_limit;
+ /*
+ * idle_spawn_rate is the number of children that will be spawned on the
+ * next maintenance cycle if there aren't enough idle servers. It is
+ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
+ * without the need to spawn.
+ */
+ int idle_spawn_rate;
+#ifndef MAX_SPAWN_RATE
+#define MAX_SPAWN_RATE (32)
+#endif
+ int hold_off_on_exponential_spawning;
} worker_retained_data;
static worker_retained_data *retained;
#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
-/*
- * The max child slot ever assigned, preserved across restarts. Necessary
- * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
- * use this value to optimize routines that have to scan the entire
- * scoreboard.
- */
-static int max_daemons_limit = -1;
-
static ap_worker_pod_t *pod;
/* The worker MPM respects a couple of runtime flags that can aid
}
}
-static apr_status_t worker_query(int query_code, int *result)
+static int worker_query(int query_code, int *result, apr_status_t *rv)
{
- switch(query_code){
+ *rv = APR_SUCCESS;
+ switch (query_code) {
case AP_MPMQ_MAX_DAEMON_USED:
- *result = max_daemons_limit;
- return APR_SUCCESS;
+ *result = retained->max_daemons_limit;
+ break;
case AP_MPMQ_IS_THREADED:
*result = AP_MPMQ_STATIC;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_IS_FORKED:
*result = AP_MPMQ_DYNAMIC;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_HARD_LIMIT_DAEMONS:
*result = server_limit;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_HARD_LIMIT_THREADS:
*result = thread_limit;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MAX_THREADS:
*result = threads_per_child;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MIN_SPARE_DAEMONS:
*result = 0;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MIN_SPARE_THREADS:
*result = min_spare_threads;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MAX_SPARE_DAEMONS:
*result = 0;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MAX_SPARE_THREADS:
*result = max_spare_threads;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MAX_REQUESTS_DAEMON:
*result = ap_max_requests_per_child;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MAX_DAEMONS:
*result = ap_daemons_limit;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_MPM_STATE:
*result = mpm_state;
- return APR_SUCCESS;
+ break;
case AP_MPMQ_GENERATION:
- *result = my_generation;
- return APR_SUCCESS;
+ *result = retained->my_generation;
+ break;
+ default:
+ *rv = APR_ENOTIMPL;
+ break;
}
- return APR_ENOTIMPL;
+ return OK;
}
-static pid_t worker_get_child_pid(int childnum)
+static void worker_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
{
- return ap_scoreboard_image->parent[childnum].pid;
+ if (childnum != -1) { /* child had a scoreboard slot? */
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[childnum].pid,
+ ap_scoreboard_image->parent[childnum].generation,
+ childnum, MPM_CHILD_EXITED);
+ ap_scoreboard_image->parent[childnum].pid = 0;
+ }
+ else {
+ ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
+ }
}
-static apr_status_t worker_note_child_killed(int childnum)
+static void worker_note_child_started(int slot, pid_t pid)
{
- ap_scoreboard_image->parent[childnum].pid = 0;
- return APR_SUCCESS;
+ 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);
+}
+
+static void worker_note_child_lost_slot(int slot, pid_t newpid)
+{
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
+ "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
+ "%" APR_PID_T_FMT "%s",
+ newpid,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].quiescing ?
+ " (quiescing)" : "");
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation,
+ slot, MPM_CHILD_LOST_SLOT);
+ /* Don't forget about this exiting child process, or we
+ * won't be able to kill it if it doesn't exit by the
+ * time the server is shut down.
+ */
+ ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation);
}
static const char *worker_get_name(void)
if (pchild) {
apr_pool_destroy(pchild);
}
+
+ if (one_process) {
+ worker_note_child_killed(/* slot */ 0, 0, 0);
+ }
+
exit(code);
}
* Connection structures and accounting...
*/
-/* volatile just in case */
+static int child_fatal;
+
+/* volatile because they're updated from a signal handler */
static int volatile shutdown_pending;
static int volatile restart_pending;
-static int volatile is_graceful;
-static volatile int child_fatal;
/*
* ap_start_shutdown() and ap_start_restart(), below, are a first stab at
return;
}
shutdown_pending = 1;
- is_graceful = graceful;
+ retained->is_graceful = graceful;
}
/* do a graceful restart if graceful == 1 */
return;
}
restart_pending = 1;
- is_graceful = graceful;
+ retained->is_graceful = graceful;
}
static void sig_term(int sig)
"sigaction(SIGXCPU)");
#endif
#ifdef SIGXFSZ
- sa.sa_handler = SIG_DFL;
+ /* 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,
"sigaction(SIGXFSZ)");
apr_signal(SIGXCPU, SIG_DFL);
#endif /* SIGXCPU */
#ifdef SIGXFSZ
- apr_signal(SIGXFSZ, SIG_DFL);
+ apr_signal(SIGXFSZ, SIG_IGN);
#endif /* SIGXFSZ */
}
}
/* requests_this_child has gone to zero or below. See if the admin coded
- "MaxRequestsPerChild 0", and keep going in that case. Doing it this way
+ "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way
simplifies the hot path in worker_thread */
static void check_infinite_requests(void)
{
signal_threads(ST_GRACEFUL);
}
else {
- /* wow! if you're executing this code, you may have set a record.
- * either this child process has served over 2 billion requests, or
- * you're running a threaded 2.0 on a 16 bit machine.
- *
- * I'll buy pizza and beers at Apachecon for the first person to do
- * the former without cheating (dorking with INT_MAX, or running with
- * uncommitted performance patches, for example).
- *
- * for the latter case, you probably deserve a beer too. Greg Ames
- */
-
requests_this_child = INT_MAX; /* keep going */
}
}
*/
}
+static void accept_mutex_error(const char *func, apr_status_t rv, int process_slot)
+{
+ int level = APLOG_EMERG;
+
+ if (ap_scoreboard_image->parent[process_slot].generation !=
+ ap_scoreboard_image->global->running_generation) {
+ level = APLOG_DEBUG; /* common to get these at restart time */
+ }
+ else if (requests_this_child == INT_MAX
+ || ((requests_this_child == ap_max_requests_per_child)
+ && ap_max_requests_per_child)) {
+ ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
+ "apr_proc_mutex_%s failed "
+ "before this child process served any requests.",
+ func);
+ clean_child_exit(APEXIT_CHILDSICK);
+ }
+ ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
+ "apr_proc_mutex_%s failed. Attempting to "
+ "shutdown process gracefully.", func);
+ signal_threads(ST_GRACEFUL);
+}
+
static void * APR_THREAD_FUNC listener_thread(apr_thread_t *thd, void * dummy)
{
proc_info * ti = dummy;
free(ti);
- /* ### check the status */
- (void) apr_pollset_create(&pollset, num_listensocks, tpool, 0);
+ rv = apr_pollset_create(&pollset, num_listensocks, tpool, 0);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "Couldn't create pollset in thread;"
+ " check system or user limits");
+ /* let the parent decide how bad this really is */
+ clean_child_exit(APEXIT_CHILDSICK);
+ }
for (lr = ap_listeners; lr != NULL; lr = lr->next) {
apr_pollfd_t pfd = { 0 };
pfd.reqevents = APR_POLLIN;
pfd.client_data = lr;
- /* ### check the status */
- (void) apr_pollset_add(pollset, &pfd);
+ rv = apr_pollset_add(pollset, &pfd);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ "Couldn't create add listener to pollset;"
+ " check system or user limits");
+ /* let the parent decide how bad this really is */
+ clean_child_exit(APEXIT_CHILDSICK);
+ }
lr->accept_func = ap_unixd_accept;
}
if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(accept_mutex)))
!= APR_SUCCESS) {
- int level = APLOG_EMERG;
- if (listener_may_exit) {
- break;
+ if (!listener_may_exit) {
+ accept_mutex_error("lock", rv, process_slot);
}
- if (ap_scoreboard_image->parent[process_slot].generation !=
- ap_scoreboard_image->global->running_generation) {
- level = APLOG_DEBUG; /* common to get these at restart time */
- }
- ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
- "apr_proc_mutex_lock failed. Attempting to shutdown "
- "process gracefully.");
- signal_threads(ST_GRACEFUL);
break; /* skip the lock release */
}
/* apr_pollset_poll() will only return errors in catastrophic
* circumstances. Let's try exiting gracefully, for now. */
- ap_log_error(APLOG_MARK, APLOG_ERR, rv,
- (const server_rec *) ap_server_conf,
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
"apr_pollset_poll: (listen)");
signal_threads(ST_GRACEFUL);
}
}
if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex)))
!= APR_SUCCESS) {
- int level = APLOG_EMERG;
if (listener_may_exit) {
break;
}
- if (ap_scoreboard_image->parent[process_slot].generation !=
- ap_scoreboard_image->global->running_generation) {
- level = APLOG_DEBUG; /* common to get these at restart time */
- }
- ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
- "apr_proc_mutex_unlock failed. Attempting to "
- "shutdown process gracefully.");
- signal_threads(ST_GRACEFUL);
+ accept_mutex_error("unlock", rv, process_slot);
}
if (csd != NULL) {
rv = ap_queue_push(worker_queue, csd, ptrans);
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 = my_generation;
+ ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation;
ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL);
#ifdef HAVE_PTHREAD_KILL
/*stuff to do before we switch id's, so we have permissions.*/
ap_reopen_scoreboard(pchild, NULL, 0);
- rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname,
+ rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex,
+ apr_proc_mutex_lockfile(accept_mutex),
pchild));
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
else { /* !one_process */
/* remove SIGTERM from the set of blocked signals... if one of
* the other threads in the process needs to take us down
- * (e.g., for MaxRequestsPerChild) it will send us SIGTERM
+ * (e.g., for MaxConnectionsPerChild) it will send us SIGTERM
*/
unblock_signal(SIGTERM);
apr_signal(SIGTERM, dummy_signal_handler);
{
int pid;
- if (slot + 1 > max_daemons_limit) {
- max_daemons_limit = slot + 1;
+ if (slot + 1 > retained->max_daemons_limit) {
+ retained->max_daemons_limit = slot + 1;
}
if (one_process) {
set_signals();
- ap_scoreboard_image->parent[slot].pid = getpid();
+ worker_note_child_started(slot, getpid());
child_main(slot);
+ /* NOTREACHED */
}
if ((pid = fork()) == -1) {
int status = bindprocessor(BINDPROCESS, (int)getpid(),
PROCESSOR_CLASS_ANY);
if (status != OK)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, errno,
ap_server_conf,
- "processor unbind failed %d", status);
+ "processor unbind failed");
#endif
RAISE_SIGSTOP(MAKE_CHILD);
apr_signal(SIGTERM, just_die);
child_main(slot);
-
- clean_child_exit(0);
+ /* NOTREACHED */
}
/* else */
if (ap_scoreboard_image->parent[slot].pid != 0) {
/* This new child process is squatting on the scoreboard
* entry owned by an exiting child process, which cannot
* exit until all active requests complete.
- * Don't forget about this exiting child process, or we
- * won't be able to kill it if it doesn't exit by the
- * time the server is shut down.
*/
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
- "taking over scoreboard slot from %" APR_PID_T_FMT "%s",
- ap_scoreboard_image->parent[slot].pid,
- ap_scoreboard_image->parent[slot].quiescing ?
- " (quiescing)" : "");
- ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid);
+ worker_note_child_lost_slot(slot, pid);
}
ap_scoreboard_image->parent[slot].quiescing = 0;
- ap_scoreboard_image->parent[slot].pid = pid;
+ worker_note_child_started(slot, pid);
return 0;
}
}
}
-
-/*
- * idle_spawn_rate is the number of children that will be spawned on the
- * next maintenance cycle if there aren't enough idle servers. It is
- * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
- * without the need to spawn.
- */
-static int idle_spawn_rate = 1;
-#ifndef MAX_SPAWN_RATE
-#define MAX_SPAWN_RATE (32)
-#endif
-static int hold_off_on_exponential_spawning;
-
static void perform_idle_server_maintenance(void)
{
int i, j;
int any_dead_threads = 0;
int all_dead_threads = 1;
- if (i >= max_daemons_limit && totally_free_length == idle_spawn_rate)
+ if (i >= retained->max_daemons_limit && totally_free_length == retained->idle_spawn_rate)
/* short cut if all active processes have been examined and
* enough empty scoreboard slots have been found
*/
loop if no pid? not much else matters */
if (status <= SERVER_READY &&
!ps->quiescing &&
- ps->generation == my_generation) {
+ ps->generation == retained->my_generation) {
++idle_thread_count;
}
if (status >= SERVER_READY && status < SERVER_GRACEFUL) {
}
}
}
- if (any_dead_threads && totally_free_length < idle_spawn_rate
+ if (any_dead_threads && totally_free_length < retained->idle_spawn_rate
&& free_length < MAX_SPAWN_RATE
&& (!ps->pid /* no process in the slot */
|| ps->quiescing)) { /* or at least one is going away */
}
}
- if (sick_child_detected) {
+ if (retained->sick_child_detected) {
if (active_thread_count > 0) {
/* some child processes appear to be working. don't kill the
* whole server.
*/
- sick_child_detected = 0;
+ retained->sick_child_detected = 0;
}
else {
/* looks like a basket case. give up.
}
}
- max_daemons_limit = last_non_dead + 1;
+ retained->max_daemons_limit = last_non_dead + 1;
if (idle_thread_count > max_spare_threads) {
/* Kill off one child */
ap_worker_pod_signal(pod, TRUE);
- idle_spawn_rate = 1;
+ retained->idle_spawn_rate = 1;
}
else if (idle_thread_count < min_spare_threads) {
/* terminate the free list */
if (free_length == 0) { /* scoreboard is full, can't fork */
if (active_thread_count >= ap_daemons_limit * threads_per_child) {
- static int reported = 0;
- if (!reported) {
- /* only report this condition once */
- ap_log_error(APLOG_MARK, APLOG_ERR, 0,
- ap_server_conf,
- "server reached MaxClients setting, consider"
- " raising the MaxClients setting");
- reported = 1;
+ /* no threads are "inactive" - starting, stopping, etc. */
+ /* have we reached MaxClients, or just getting close? */
+ if (0 == idle_thread_count) {
+ if (!retained->maxclients_reported) {
+ /* only report this condition once */
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+ ap_server_conf,
+ "server reached MaxClients setting, consider"
+ " raising the MaxClients setting");
+ retained->maxclients_reported = 1;
+ }
+ } else {
+ if (!retained->near_maxclients_reported) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+ ap_server_conf,
+ "server is within MinSpareThreads of MaxClients, "
+ "consider raising the MaxClients setting");
+ retained->near_maxclients_reported = 1;
+ }
}
}
else {
ap_server_conf,
"scoreboard is full, not at MaxClients");
}
- idle_spawn_rate = 1;
+ retained->idle_spawn_rate = 1;
}
else {
- if (free_length > idle_spawn_rate) {
- free_length = idle_spawn_rate;
+ if (free_length > retained->idle_spawn_rate) {
+ free_length = retained->idle_spawn_rate;
}
- if (idle_spawn_rate >= 8) {
+ if (retained->idle_spawn_rate >= 8) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0,
ap_server_conf,
"server seems busy, (you may need "
/* the next time around we want to spawn twice as many if this
* wasn't good enough, but not if we've just done a graceful
*/
- if (hold_off_on_exponential_spawning) {
- --hold_off_on_exponential_spawning;
+ if (retained->hold_off_on_exponential_spawning) {
+ --retained->hold_off_on_exponential_spawning;
}
- else if (idle_spawn_rate < MAX_SPAWN_RATE) {
- idle_spawn_rate *= 2;
+ else if (retained->idle_spawn_rate < MAX_SPAWN_RATE) {
+ retained->idle_spawn_rate *= 2;
}
}
}
else {
- idle_spawn_rate = 1;
+ retained->idle_spawn_rate = 1;
}
}
static void server_main_loop(int remaining_children_to_start)
{
+ ap_generation_t old_gen;
int child_slot;
apr_exit_why_e exitwhy;
int status, processed_status;
int i;
while (!restart_pending && !shutdown_pending) {
- ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
+ ap_wait_or_timeout(&exitwhy, &status, &pid, pconf, ap_server_conf);
if (pid.pid != -1) {
processed_status = ap_process_child_status(&pid, exitwhy, status);
/* tell perform_idle_server_maintenance to check into this
* on the next timer pop
*/
- sick_child_detected = 1;
+ retained->sick_child_detected = 1;
}
/* non-fatal death... note that it's gone in the scoreboard. */
child_slot = ap_find_child_by_pid(&pid);
ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
(request_rec *) NULL);
- ap_scoreboard_image->parent[child_slot].pid = 0;
+ worker_note_child_killed(child_slot, 0, 0);
ap_scoreboard_image->parent[child_slot].quiescing = 0;
if (processed_status == APEXIT_CHILDSICK) {
/* resource shortage, minimize the fork rate */
- idle_spawn_rate = 1;
+ retained->idle_spawn_rate = 1;
}
else if (remaining_children_to_start
&& child_slot < ap_daemons_limit) {
--remaining_children_to_start;
}
}
- else if (ap_unregister_extra_mpm_process(pid.pid) == 1) {
- /* handled */
+ else if (ap_unregister_extra_mpm_process(pid.pid, &old_gen) == 1) {
+ worker_note_child_killed(-1, /* already out of the scoreboard */
+ pid.pid, old_gen);
#if APR_HAS_OTHER_CHILD
}
else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
/* handled */
#endif
}
- else if (is_graceful) {
+ else if (retained->is_graceful) {
/* Great, we've probably just lost a slot in the
* scoreboard. Somehow we don't know about this child.
*/
ap_log_pid(pconf, ap_pid_fname);
/* Initialize cross-process accept lock */
- ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT,
- ap_server_root_relative(_pconf, ap_lock_fname),
- ap_my_pid);
-
- rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,
- ap_accept_lock_mech, _pconf);
+ rv = ap_proc_mutex_create(&accept_mutex, NULL, AP_ACCEPT_MUTEX_TYPE, NULL,
+ s, _pconf, 0);
if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
- "Couldn't create accept lock");
mpm_state = AP_MPMQ_STOPPING;
- return 1;
- }
-
-#if APR_USE_SYSVSEM_SERIALIZE
- if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
- ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
-#else
- if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
-#endif
- rv = ap_unixd_set_proc_mutex_perms(accept_mutex);
- if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
- "Couldn't set permissions on cross-process lock; "
- "check User and Group directives");
- mpm_state = AP_MPMQ_STOPPING;
- return 1;
- }
+ return DONE;
}
- if (!is_graceful) {
+ if (!retained->is_graceful) {
if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
mpm_state = AP_MPMQ_STOPPING;
- return 1;
+ return DONE;
}
/* fix the generation number in the global score; we just got a new,
* cleared scoreboard
*/
- ap_scoreboard_image->global->running_generation = my_generation;
+ ap_scoreboard_image->global->running_generation = retained->my_generation;
}
set_signals();
if (remaining_children_to_start > ap_daemons_limit) {
remaining_children_to_start = ap_daemons_limit;
}
- if (!is_graceful) {
+ if (!retained->is_graceful) {
startup_children(remaining_children_to_start);
remaining_children_to_start = 0;
}
else {
/* give the system some time to recover before kicking into
* exponential mode */
- hold_off_on_exponential_spawning = 10;
+ retained->hold_off_on_exponential_spawning = 10;
}
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
ap_get_server_description());
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
"Server built: %s", ap_get_server_built());
+ ap_log_command_line(plog, s);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
- "AcceptMutex: %s (default: %s)",
+ "Accept mutex: %s (default: %s)",
apr_proc_mutex_name(accept_mutex),
apr_proc_mutex_defname());
restart_pending = shutdown_pending = 0;
server_main_loop(remaining_children_to_start);
mpm_state = AP_MPMQ_STOPPING;
- if (shutdown_pending && !is_graceful) {
+ if (shutdown_pending && !retained->is_graceful) {
/* Time to shut down:
* Kill child processes, tell them to call child_exit, etc...
*/
ap_worker_pod_killpg(pod, ap_daemons_limit, FALSE);
- ap_reclaim_child_processes(1); /* Start with SIGTERM */
+ ap_reclaim_child_processes(1, /* Start with SIGTERM */
+ worker_note_child_killed);
if (!child_fatal) {
/* cleanup pid file on normal shutdown */
- const char *pidfile = NULL;
- pidfile = ap_server_root_relative (pconf, ap_pid_fname);
- if ( pidfile != NULL && unlink(pidfile) == 0)
- ap_log_error(APLOG_MARK, APLOG_INFO, 0,
- ap_server_conf,
- "removed PID file %s (pid=%" APR_PID_T_FMT ")",
- pidfile, getpid());
-
+ ap_remove_pid(pconf, ap_pid_fname);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
ap_server_conf, "caught SIGTERM, shutting down");
}
- return 1;
+ return DONE;
} else if (shutdown_pending) {
/* Time to gracefully shut down:
* Kill child processes, tell them to call child_exit, etc...
/* Close our listeners, and then ask our children to do same */
ap_close_listeners();
ap_worker_pod_killpg(pod, ap_daemons_limit, TRUE);
- ap_relieve_child_processes();
+ ap_relieve_child_processes(worker_note_child_killed);
if (!child_fatal) {
/* cleanup pid file on normal shutdown */
- const char *pidfile = NULL;
- pidfile = ap_server_root_relative (pconf, ap_pid_fname);
- if ( pidfile != NULL && unlink(pidfile) == 0)
- ap_log_error(APLOG_MARK, APLOG_INFO, 0,
- ap_server_conf,
- "removed PID file %s (pid=%" APR_PID_T_FMT ")",
- pidfile, getpid());
-
+ ap_remove_pid(pconf, ap_pid_fname);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
"caught " AP_SIG_GRACEFUL_STOP_STRING
", shutting down gracefully");
apr_sleep(apr_time_from_sec(1));
/* Relieve any children which have now exited */
- ap_relieve_child_processes();
+ ap_relieve_child_processes(worker_note_child_killed);
active_children = 0;
for (index = 0; index < ap_daemons_limit; ++index) {
* really dead.
*/
ap_worker_pod_killpg(pod, ap_daemons_limit, FALSE);
- ap_reclaim_child_processes(1);
+ ap_reclaim_child_processes(1, worker_note_child_killed);
- return 1;
+ return DONE;
}
/* we've been told to restart */
if (one_process) {
/* not worth thinking about */
- return 1;
+ 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.
*/
- ++my_generation;
- ap_scoreboard_image->global->running_generation = my_generation;
+ ++retained->my_generation;
+ ap_scoreboard_image->global->running_generation = retained->my_generation;
- if (is_graceful) {
+ if (retained->is_graceful) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
AP_SIG_GRACEFUL_STRING " received. Doing graceful restart");
/* wake up the children...time to die. But we'll have more soon */
*/
ap_worker_pod_killpg(pod, ap_daemons_limit, FALSE);
- ap_reclaim_child_processes(1); /* Start with SIGTERM */
+ ap_reclaim_child_processes(1, /* Start with SIGTERM */
+ worker_note_child_killed);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
"SIGHUP received. Attempting to restart");
}
foreground = ap_exists_config_define("FOREGROUND");
}
+ ap_mutex_register(pconf, AP_ACCEPT_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0);
+
/* sigh, want this only the second time around */
- retained = ap_get_retained_data(userdata_key);
+ retained = ap_retained_data_get(userdata_key);
if (!retained) {
- retained = ap_set_retained_data(userdata_key, sizeof(*retained));
+ retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+ retained->max_daemons_limit = -1;
+ retained->idle_spawn_rate = 1;
}
++retained->module_loads;
if (retained->module_loads == 2) {
- is_graceful = 0;
-
if (!one_process && !foreground) {
rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
: APR_PROC_DETACH_DAEMONIZE);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
- parent_pid = ap_my_pid = getpid();
}
+ parent_pid = ap_my_pid = getpid();
+
ap_listen_pre_config();
ap_daemons_to_start = DEFAULT_START_DAEMON;
min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
ap_daemons_limit = server_limit;
threads_per_child = DEFAULT_THREADS_PER_CHILD;
max_clients = ap_daemons_limit * threads_per_child;
- ap_pid_fname = DEFAULT_PIDLOG;
- ap_lock_fname = DEFAULT_LOCKFILE;
- ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
ap_extended_status = 0;
- ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
-
- apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
return OK;
}
static int worker_check_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
- static int restart_num = 0;
int startup = 0;
/* the reverse of pre_config, we want this only the first time around */
- if (restart_num++ == 0) {
+ if (retained->module_loads == 1) {
startup = 1;
}
ap_hook_check_config(worker_check_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm(worker_run, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_query(worker_query, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_mpm_get_child_pid(worker_get_child_pid, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_mpm_note_child_killed(worker_note_child_killed, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_get_name(worker_get_name, NULL, NULL, APR_HOOK_MIDDLE);
}
{ NULL }
};
-module AP_MODULE_DECLARE_DATA mpm_worker_module = {
+AP_DECLARE_MODULE(mpm_worker) = {
MPM20_MODULE_STUFF,
- ap_mpm_rewrite_args, /* hook to run before apache parses args */
+ NULL, /* hook to run before apache parses args */
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */