worker.c revision 024e70e05386a6367eb45d0d1cc406764520ff4c
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* Licensed to the Apache Software Foundation (ASF) under one or more
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * contributor license agreements. See the NOTICE file distributed with
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * this work for additional information regarding copyright ownership.
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * The ASF licenses this file to You under the Apache License, Version 2.0
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * (the "License"); you may not use this file except in compliance with
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * the License. You may obtain a copy of the License at
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * Unless required by applicable law or agreed to in writing, software
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * distributed under the License is distributed on an "AS IS" BASIS,
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * See the License for the specific language governing permissions and
2e545ce2450a9953665f701bb05350f0d3f26275nd * limitations under the License.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* The purpose of this MPM is to fix the design flaws in the threaded
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * model. Because of the way that pthreads and mutex locks interact,
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * it is basically impossible to cleanly gracefully shutdown a child
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * process if multiple threads are all blocked in accept. This model
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * fixes those problems.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor#error The Worker MPM requires APR threads, but they are unavailable.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* Limit on the total --- clients will be locked out if more servers than
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * this are needed. It is intended solely to keep the server from crashing
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * when things get out of hand.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * We keep a hard maximum number of servers, for two reasons --- first off,
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * in case something goes seriously wrong, we want to stop the fork bomb
01f52ba6a87aa39d3873a441369828875c471823trawick * short of actually crashing the machine we're running on by filling some
01f52ba6a87aa39d3873a441369828875c471823trawick * kernel table. Secondly, it keeps the size of the scoreboard file small
01f52ba6a87aa39d3873a441369828875c471823trawick * enough that we can read the whole thing without worrying too much about
01f52ba6a87aa39d3873a441369828875c471823trawick * the overhead.
01f52ba6a87aa39d3873a441369828875c471823trawick/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
01f52ba6a87aa39d3873a441369828875c471823trawick * some sort of compile-time limit to help catch typos.
4aa603e6448b99f9371397d439795c91a93637eand/* Limit on the threads per process. Clients will be locked out if more than
4aa603e6448b99f9371397d439795c91a93637eand * this * server_limit are needed.
01f52ba6a87aa39d3873a441369828875c471823trawick * We keep this for one reason it keeps the size of the scoreboard file small
01f52ba6a87aa39d3873a441369828875c471823trawick * enough that we can read the whole thing without worrying too much about
01f52ba6a87aa39d3873a441369828875c471823trawick * the overhead.
4aa603e6448b99f9371397d439795c91a93637eand/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
4aa603e6448b99f9371397d439795c91a93637eand * some sort of compile-time limit to help catch typos.
01f52ba6a87aa39d3873a441369828875c471823trawick * Actual definitions of config globals
4aa603e6448b99f9371397d439795c91a93637eandstatic int threads_per_child = 0; /* Worker threads per child */
4aa603e6448b99f9371397d439795c91a93637eandstatic int ap_daemons_to_start = 0;
01f52ba6a87aa39d3873a441369828875c471823trawickstatic int min_spare_threads = 0;
01f52ba6a87aa39d3873a441369828875c471823trawickstatic int max_spare_threads = 0;
01f52ba6a87aa39d3873a441369828875c471823trawickstatic int ap_daemons_limit = 0;
01f52ba6a87aa39d3873a441369828875c471823trawickstatic int max_clients = 0;
01f52ba6a87aa39d3873a441369828875c471823trawickstatic int server_limit = 0;
01f52ba6a87aa39d3873a441369828875c471823trawickstatic int thread_limit = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic int dying = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic int workers_may_exit = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic int listener_may_exit = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic int num_listensocks = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic int resource_shortage = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* data retained by worker across load/unload of the module
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * allocated on first call to pre-config hook; located on
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * subsequent calls to pre-config hook
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzortypedef struct worker_retained_data {
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* The structure used to pass unique initialization info to each thread */
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzortypedef struct {
4aa603e6448b99f9371397d439795c91a93637eand/* Structure used to pass information to the thread responsible for
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * creating the rest of the threads.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzortypedef struct {
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * The max child slot ever assigned, preserved across restarts. Necessary
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * use this value to optimize routines that have to scan the entire
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * scoreboard.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* The worker MPM respects a couple of runtime flags that can aid
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * in debugging. Setting the -DNO_DETACH flag will prevent the root process
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * from detaching from its controlling terminal. Additionally, setting
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * child_main loop running in the process which originally started up.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * early in standalone_main; just continue through. This is the server
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * trying to kill off any child processes which it might have lying
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * around --- Apache doesn't keep track of their pids, it just sends
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * SIGHUP to the process group, ignoring it in the root process.
853ab6827637acc5cdd976cd2ea20a18f82ae184lgentis * Continue through and you'll be fine.).
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic int one_process = 0;
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzorstatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor thread. Use this instead */
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* Locks for accept serialization */
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* The LISTENER_SIGNAL signal will be sent from the main thread to the
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * listener thread to wake it up for graceful termination (what a child
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * process from an old generation does when the admin does "apachectl
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * graceful"). This signal will be blocked in all threads of a child
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * process except for the listener thread.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor/* The WORKER_SIGNAL signal will be sent from the main thread to the
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * worker threads during an ungraceful restart or shutdown.
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * This ensures that on systems (i.e., Linux) where closing the worker
0f40f560dcfc0a192b0d92b8dc00b13e980bfe9dgryzor * socket doesn't awake the worker thread when it is polling on the socket
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * (especially in apr_wait_for_io_or_timeout() when handling
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Keep-Alive connections), close_worker_sockets() and join_workers()
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * still function in timely manner and allow ungraceful shutdowns to
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * proceed to completion. Otherwise join_workers() doesn't return
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * before the main process decides the child process is non-responsive
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * and sends a SIGKILL.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar/* An array of socket descriptors in use by each thread used to
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * perform a non-graceful (forced) shutdown of the server. */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic void close_worker_sockets(void)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar for (i = 0; i < threads_per_child; i++) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic void wakeup_listener(void)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* XXX there is an obscure path that this doesn't handle perfectly:
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * right after listener thread is created but before
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * listener_os_thread is set, the first worker thread hits an
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * error and starts graceful termination
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* unblock the listener if it's waiting for a worker */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * platforms and wake up the listener thread since it is the only thread
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * with SIGHUP unblocked, but that doesn't work on Linux
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* in case we weren't called from the listener thread, wake up the
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * listener thread
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* for ungraceful termination, let the workers exit now;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * for graceful termination, the listener thread will notify the
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * workers to exit once it has stopped accepting new connections
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar close_worker_sockets(); /* forcefully kill all current connections */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic int worker_query(int query_code, int *result, apr_status_t *rv)
case AP_MPMQ_GENERATION:
return OK;
return APR_SUCCESS;
static const char *worker_get_name(void)
if (pchild) {
clean_child_exit(0);
static int volatile shutdown_pending;
static int volatile restart_pending;
static int volatile is_graceful;
static volatile int child_fatal;
static void set_signals(void)
#ifndef NO_USE_SIGACTION
if (!one_process) {
#ifndef NO_USE_SIGACTION
#ifdef AP_SIG_GRACEFUL_STOP
#ifdef SIGINT
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGPIPE
if (!one_process) {
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGHUP
#ifdef AP_SIG_GRACEFUL
#ifdef AP_SIG_GRACEFUL_STOP
#ifdef SIGPIPE
int my_child_num,
if (current_conn) {
static void check_infinite_requests(void)
if (ap_max_requests_per_child) {
#if defined(SIGPROCMASK_SETS_THREAD_MASK)
&& ap_max_requests_per_child)) {
func);
int have_idle_worker = 0;
int last_poll_idx = 0;
if (requests_this_child <= 0) {
if (listener_may_exit) break;
if (!have_idle_worker) {
&ptrans);
!= APR_SUCCESS) {
if (!listener_may_exit) {
while (!listener_may_exit) {
if (listener_may_exit) break;
last_poll_idx = 0;
if (!listener_may_exit) {
!= APR_SUCCESS) {
if (listener_may_exit) {
if (rv) {
have_idle_worker = 0;
!= APR_SUCCESS) {
return NULL;
/* XXX For ungraceful termination/restart, we definitely don't want to
int is_idle = 0;
#ifdef HAVE_PTHREAD_KILL
while (!workers_may_exit) {
if (!is_idle) {
if (workers_may_exit) {
goto worker_pop;
else if (!workers_may_exit) {
is_idle = 0;
return NULL;
switch (signum) {
case SIGTERM:
case SIGINT:
int threads_created = 0;
int listener_started = 0;
int loops;
int prev_threads_created;
* sizeof(apr_socket_t *));
for (i = 0; i < threads_per_child; i++) {
++loops;
return NULL;
if (listener) {
int iter;
iter = 0;
#ifdef HAVE_PTHREAD_KILL
++iter;
for (i = 0; i < threads_per_child; i++) {
#ifdef HAVE_PTHREAD_KILL
pchild));
if (ap_max_requests_per_child) {
if (ap_thread_stacksize != 0) {
if (one_process) {
switch(terminate_mode) {
case ST_GRACEFUL:
case ST_UNGRACEFUL:
int pid;
if (one_process) {
set_signals();
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
clean_child_exit(0);
#ifndef MAX_SPAWN_RATE
static int hold_off_on_exponential_spawning;
static void perform_idle_server_maintenance(void)
int idle_thread_count;
int free_length;
int totally_free_length = 0;
int last_non_dead;
int total_non_dead;
int active_thread_count = 0;
free_length = 0;
idle_thread_count = 0;
total_non_dead = 0;
for (i = 0; i < ap_daemons_limit; ++i) {
int any_dying_threads = 0;
int any_dead_threads = 0;
for (j = 0; j < threads_per_child; j++) {
if (all_dead_threads) {
++free_length;
if (!any_dying_threads) {
last_non_dead = i;
if (sick_child_detected) {
if (active_thread_count > 0) {
sick_child_detected = 0;
if (0 == idle_thread_count) {
static int reported = 0;
if (!reported) {
static int reported = 0;
if (!reported) {
"or Min/MaxSpareThreads), "
for (i = 0; i < free_length; ++i) {
int child_slot;
if (child_slot >= 0) {
for (i = 0; i < threads_per_child; i++)
else if (remaining_children_to_start
status) == 0) {
else if (is_graceful) {
else if (remaining_children_to_start) {
s, _pconf, 0);
return DONE;
if (!is_graceful) {
return DONE;
set_signals();
if (!is_graceful) {
if (!child_fatal) {
return DONE;
} else if (shutdown_pending) {
int active_children;
int index;
if (!child_fatal) {
if (ap_graceful_shutdown_timeout) {
shutdown_pending = 0;
active_children = 0;
return DONE;
if (one_process) {
return DONE;
if (is_graceful) {
/* wake up the children...time to die. But we'll have more soon */
return OK;
int startup = 0;
int level_flags = 0;
pconf = p;
return DONE;
if (!one_process) {
return DONE;
return OK;
if (debug) {
no_detach = 0;
if (!retained) {
is_graceful = 0;
return HTTP_INTERNAL_SERVER_ERROR;
ap_extended_status = 0;
return OK;
static int restart_num = 0;
int startup = 0;
if (restart_num++ == 0) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (ap_daemons_to_start < 0) {
if (startup) {
if (startup) {
return OK;
one_process = 0;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
"Maximum number of worker threads per child process for this run of Apache - Upper limit for ThreadsPerChild"),
{ NULL }