threaded.c revision f44d73842e45390adaecf468eb99d6654e29c33d
2d2eda71267231c2526be701fe655db125852c1ffielding/* ====================================================================
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * The Apache Software License, Version 1.1
b99dbaab171d91e1b664397cc40e039d0c087c65fielding * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * reserved.
2d2eda71267231c2526be701fe655db125852c1ffielding * Redistribution and use in source and binary forms, with or without
2d2eda71267231c2526be701fe655db125852c1ffielding * modification, are permitted provided that the following conditions
2d2eda71267231c2526be701fe655db125852c1ffielding * 1. Redistributions of source code must retain the above copyright
2d2eda71267231c2526be701fe655db125852c1ffielding * notice, this list of conditions and the following disclaimer.
2d2eda71267231c2526be701fe655db125852c1ffielding * 2. Redistributions in binary form must reproduce the above copyright
2d2eda71267231c2526be701fe655db125852c1ffielding * notice, this list of conditions and the following disclaimer in
2d2eda71267231c2526be701fe655db125852c1ffielding * the documentation and/or other materials provided with the
2d2eda71267231c2526be701fe655db125852c1ffielding * distribution.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * 3. The end-user documentation included with the redistribution,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * if any, must include the following acknowledgment:
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * "This product includes software developed by the
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Apache Software Foundation (http://www.apache.org/)."
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Alternately, this acknowledgment may appear in the software itself,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * if and wherever such third-party acknowledgments normally appear.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * 4. The names "Apache" and "Apache Software Foundation" must
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * not be used to endorse or promote products derived from this
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * software without prior written permission. For written
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * permission, please contact apache@apache.org.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * 5. Products derived from this software may not be called "Apache",
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * nor may "Apache" appear in their name, without prior written
64185f9824e42f21ca7b9ae6c004484215c031a7rbb * permission of the Apache Software Foundation.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
2d2eda71267231c2526be701fe655db125852c1ffielding * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * SUCH DAMAGE.
2d2eda71267231c2526be701fe655db125852c1ffielding * ====================================================================
2d2eda71267231c2526be701fe655db125852c1ffielding * This software consists of voluntary contributions made by many
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * individuals on behalf of the Apache Software Foundation. For more
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * information on the Apache Software Foundation, please see
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Portions of this software are based upon public domain software
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * originally written at the National Center for Supercomputing Applications,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * University of Illinois, Urbana-Champaign.
2d2eda71267231c2526be701fe655db125852c1ffielding#include <sys/processor.h> /* for bindprocessor() */
2d2eda71267231c2526be701fe655db125852c1ffielding#error The threaded MPM requires APR threads, but they are unavailable.
3d96ee83babeec32482c9082c9426340cee8c44dwrowe * Actual definitions of config globals
59d7dc153347a9f606c5712f0fae7b65e96682d9rbbint ap_threads_per_child=0; /* Worker threads per child */
59d7dc153347a9f606c5712f0fae7b65e96682d9rbbstatic int workers_may_exit = 0;
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic int num_listensocks = 0;
59d7dc153347a9f606c5712f0fae7b65e96682d9rbb/* The structure used to pass unique initialization info to each thread */
59d7dc153347a9f606c5712f0fae7b65e96682d9rbbtypedef struct {
44da058d96ca5577a8b9fe7d6b89d79fe9a0a849wrowe * The max child slot ever assigned, preserved across restarts. Necessary
44da058d96ca5577a8b9fe7d6b89d79fe9a0a849wrowe * to deal with MaxClients changes across SIGWINCH restarts. We use this
44da058d96ca5577a8b9fe7d6b89d79fe9a0a849wrowe * value to optimize routines that have to scan the entire scoreboard.
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic apr_lock_t *pipe_of_death_mutex; /* insures that a child process only
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb consumes one character */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/* *Non*-shared http_main globals... */
59d7dc153347a9f606c5712f0fae7b65e96682d9rbb/* one_process --- debugging mode variable; can be set from the command line
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * with the -X flag. If set, this gets you the child_main loop running
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * in the process which originally started up (no detach, no make_child),
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * which is a pretty nice debugging environment. (You'll get a SIGHUP
3d96ee83babeec32482c9082c9426340cee8c44dwrowe * early in standalone_main; just continue through. This is the server
2d2eda71267231c2526be701fe655db125852c1ffielding * trying to kill off any child processes which it might have lying
59d7dc153347a9f606c5712f0fae7b65e96682d9rbb * around --- Apache doesn't keep track of their pids, it just sends
59d7dc153347a9f606c5712f0fae7b65e96682d9rbb * SIGHUP to the process group, ignoring it in the root process.
dd95dce618f5c95c71733a363f7e3c8acb02f8d4rbb * Continue through and you'll be fine.).
dd95dce618f5c95c71733a363f7e3c8acb02f8d4rbbstatic int one_process = 0;
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb thread. Use this instead */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/* Keep track of the number of worker threads currently active */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/* Locks for accept serialization */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic apr_lockmech_e_np accept_lock_mech = APR_LOCK_DEFAULT;
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic const char *lock_fname;
2d2eda71267231c2526be701fe655db125852c1ffieldingAP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/* a clean exit from a child with proper cleanup */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic void clean_child_exit(int code) __attribute__ ((noreturn));
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar/* handle all varieties of core dumping signals */
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar /* At this point we've got sig blocked, because we're still inside
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar * the signal handler. When we leave the signal handler it will
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar * be unblocked, and we'll take the signal... and coredump or whatever
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar * is appropriate for this particular Unix. In addition the parent
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar * will see the real signal we received -- whereas if we called
5d54ba1fdf6f8d7167fafcd93bef30df3906b1aecoar * abort() here, the parent would only see SIGABRT.
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/*****************************************************************
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * Connection structures and accounting...
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/* volatile just in case */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbbstatic int volatile shutdown_pending;
3d96ee83babeec32482c9082c9426340cee8c44dwrowestatic int volatile restart_pending;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int volatile is_graceful;
3ef7956b993aff4b4882c643910fb688a0e707e3ben * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
3ef7956b993aff4b4882c643910fb688a0e707e3ben * functions to initiate shutdown or restart without relying on signals.
3ef7956b993aff4b4882c643910fb688a0e707e3ben * Previously this was initiated in sig_term() and restart() signal handlers,
3ef7956b993aff4b4882c643910fb688a0e707e3ben * but we want to be able to start a shutdown/restart from other sources --
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb * e.g. on Win32, from the service manager. Now the service manager can
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb * these functions can also be called by the child processes, since global
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb * variables are no longer used to pass on the required action to the parent.
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb * These should only be called from the parent process itself, since the
c3e342e5b0b9fea6617ee16d2da02c3ef2108126dougm * parent process will use the shutdown_pending and restart_pending variables
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb * to determine whether to shutdown or restart. The child process should
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * call signal_parent() directly to tell the parent to die -- this will
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * cause neither of those variable to be set, which the parent will
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * assume means something serious is wrong (which it will be, for the
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * child to force an exit) and so do an exit anyway.
3ef7956b993aff4b4882c643910fb688a0e707e3benstatic void ap_start_shutdown(void)
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb /* Um, is this _probably_ not an error, if the user has
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * tried to do a shutdown twice quickly, so we won't
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb * worry about reporting it.
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb/* do a graceful restart if graceful == 1 */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb /* Probably not an error - don't bother reporting it */
4743e6e0c6d5bc44f086d4f0032ae41a68192dd1rbb apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard);
3ef7956b993aff4b4882c643910fb688a0e707e3benstatic void set_signals(void)
3ef7956b993aff4b4882c643910fb688a0e707e3ben ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
fd0edaa8e3d4dd67d0604ccef2e96b071db96643fielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
#ifdef SIGILL
#ifdef SIGINT
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGPIPE
if (!one_process) {
#ifdef SIGBUS
#ifdef SIGABORT
#ifdef SIGABRT
#ifdef SIGILL
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGHUP
#ifdef SIGWINCH
#ifdef SIGPIPE
int ap_graceful_stop_signalled(void)
return is_graceful;
int csd;
if (current_conn) {
static void check_infinite_requests(void)
if (ap_max_requests_per_child) {
static void check_pipe_of_death(void)
if (!workers_may_exit) {
char pipe_read_char;
for(n=0 ; n <= num_listensocks ; ++n)
if (requests_this_child <= 0) {
if (workers_may_exit) break;
!= APR_SUCCESS) {
while (!workers_may_exit) {
if (workers_may_exit) break;
goto got_fd;
curr_pollfd++;
goto got_fd;
if (!workers_may_exit) {
!= APR_SUCCESS) {
!= APR_SUCCESS) {
if (worker_thread_count == 0) {
return NULL;
switch (signum) {
case SIGTERM:
case SIGINT:
pchild));
if (unixd_setup_child()) {
if (ap_max_requests_per_child) {
worker_thread_count = 0;
for (i=0; i < ap_threads_per_child; i++) {
for (i = 0; i < ap_threads_per_child; i++) {
clean_child_exit(0);
int pid;
if (one_process) {
set_signals();
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
clean_child_exit(0);
static void wake_up_and_die(void)
for (i = 0; i < ap_daemons_limit;) {
!= APR_SUCCESS) {
#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 last_non_dead;
int total_non_dead;
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 idle_thread_addition = 0;
for (j = 0; j < ap_threads_per_child; j++) {
++free_length;
if (!all_dead_threads) {
last_non_dead = i;
if (!any_dying_threads) {
if (free_length == 0) {
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 < ap_threads_per_child; i++)
else if (is_graceful) {
else if (remaining_children_to_start) {
ap_server_conf = s;
if (!is_graceful) {
set_signals();
if (!is_graceful) {
if (shutdown_pending) {
if (one_process) {
/* wake up the children...time to die. But we'll have more soon */
if (is_graceful) {
for (i = 0; i < ap_daemons_limit; ++i) {
for (j = 0; j < ap_threads_per_child; j++) {
static int restart_num = 0;
int no_detach = 0;
is_graceful = 0;
ap_extended_status = 0;
one_process = 0;
return err;
return NULL;
const char *arg)
return err;
return NULL;
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
if (min_spare_threads <= 0) {
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "WARNING: Require MaxClients > 0, setting to 1");
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
const char *fname;
return err;
return NULL;
return err;
, NULL);
return NULL;
{ NULL }