dexter.c revision b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44c
e609c337f729875bc20e01096c7e610f45356f54nilgun/* ====================================================================
e609c337f729875bc20e01096c7e610f45356f54nilgun * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Redistribution and use in source and binary forms, with or without
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * modification, are permitted provided that the following conditions
e609c337f729875bc20e01096c7e610f45356f54nilgun * 1. Redistributions of source code must retain the above copyright
e609c337f729875bc20e01096c7e610f45356f54nilgun * notice, this list of conditions and the following disclaimer.
e609c337f729875bc20e01096c7e610f45356f54nilgun * 2. Redistributions in binary form must reproduce the above copyright
e609c337f729875bc20e01096c7e610f45356f54nilgun * notice, this list of conditions and the following disclaimer in
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * the documentation and/or other materials provided with the
2e545ce2450a9953665f701bb05350f0d3f26275nd * distribution.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 3. All advertising materials mentioning features or use of this
e609c337f729875bc20e01096c7e610f45356f54nilgun * software must display the following acknowledgment:
e609c337f729875bc20e01096c7e610f45356f54nilgun * "This product includes software developed by the Apache Group
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * for use in the Apache HTTP server project (http://www.apache.org/)."
e609c337f729875bc20e01096c7e610f45356f54nilgun * 4. The names "Apache Server" and "Apache Group" must not be used to
e609c337f729875bc20e01096c7e610f45356f54nilgun * endorse or promote products derived from this software without
e609c337f729875bc20e01096c7e610f45356f54nilgun * prior written permission. For written permission, please contact
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * apache@apache.org.
e609c337f729875bc20e01096c7e610f45356f54nilgun * 5. Products derived from this software may not be called "Apache"
e609c337f729875bc20e01096c7e610f45356f54nilgun * nor may "Apache" appear in their names without prior written
27dcd8d81085fd60aadcd8a9bad35a607b26b758nilgun * permission of the Apache Group.
e609c337f729875bc20e01096c7e610f45356f54nilgun * 6. Redistributions of any form whatsoever must retain the following
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * acknowledgment:
e609c337f729875bc20e01096c7e610f45356f54nilgun * "This product includes software developed by the Apache Group
35ac4e1a6ec5aa3cfa1a34d8f20fe8a841cc46b7rbowen * for use in the Apache HTTP server project (http://www.apache.org/)."
e609c337f729875bc20e01096c7e610f45356f54nilgun * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * OF THE POSSIBILITY OF SUCH DAMAGE.
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * ====================================================================
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * This software consists of voluntary contributions made by many
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * individuals on behalf of the Apache Group and was originally based
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * on public domain software written at the National Center for
e609c337f729875bc20e01096c7e610f45356f54nilgun * Supercomputing Applications, University of Illinois, Urbana-Champaign.
e609c337f729875bc20e01096c7e610f45356f54nilgun * For more information on the Apache Group and the Apache HTTP server
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * project, please see <http://www.apache.org/>.
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * Actual definitions of config globals
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic int threads_to_start = 0; /* Worker threads per child */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic int min_spare_threads = 0;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic int max_spare_threads = 0;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic int max_threads = 0;
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int workers_may_exit = 0;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic int num_listenfds = 0;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* Table of child status */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic struct {
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun unsigned char status;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * The max child slot ever assigned, preserved across restarts. Necessary
e609c337f729875bc20e01096c7e610f45356f54nilgun * to deal with NumServers changes across SIGWINCH restarts. We use this
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * value to optimize routines that have to scan the entire child table.
e609c337f729875bc20e01096c7e610f45356f54nilgun * XXX - It might not be worth keeping this code in. There aren't very
e609c337f729875bc20e01096c7e610f45356f54nilgun * many child processes in this MPM.
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* *Non*-shared http_main globals... */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* one_process --- debugging mode variable; can be set from the command line
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * with the -X flag. If set, this gets you the child_main loop running
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * in the process which originally started up (no detach, no make_child),
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * which is a pretty nice debugging environment. (You'll get a SIGHUP
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * early in standalone_main; just continue through. This is the server
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * trying to kill off any child processes which it might have lying
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * around --- Apache doesn't keep track of their pids, it just sends
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * SIGHUP to the process group, ignoring it in the root process.
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * Continue through and you'll be fine.).
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic int one_process = 0;
e609c337f729875bc20e01096c7e610f45356f54nilgun/* used to maintain list of children which aren't part of the child table */
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic ap_context_t *pconf; /* Pool for config stuff */
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic ap_context_t *pchild; /* Pool for httpd child stuff */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic ap_context_t *thread_pool_parent; /* Parent of per-thread pools */
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int my_pid; /* Linux getpid() doesn't work except in main thread. Use
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun this instead */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* Keep track of the number of worker threads currently active */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* Keep track of the number of idle worker threads */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* Locks for accept serialization */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun#endif /* NO_SERIALIZED_ACCEPT */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic char *lock_fname;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunstatic pthread_mutex_t thread_accept_mutex = PTHREAD_MUTEX_INITIALIZER;
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* Global, alas, so http_core can talk to us */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgunAPI_EXPORT(const server_rec *) ap_get_server_conf(void)
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/* a clean exit from a child with proper cleanup */
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun/*****************************************************************
e05e9b1990428410383f42a260dfaf9b8067f24dnilgun * dealing with other children
e609c337f729875bc20e01096c7e610f45356f54nilgun void (*maintenance) (int reason, void *, ap_wait_t status),
0d0ba3a410038e179b695446bb149cce6264e0abnd/* note that since this can be called by a maintenance function while we're
0d0ba3a410038e179b695446bb149cce6264e0abnd * scanning the other_children list, all scanners should protect themself
0d0ba3a410038e179b695446bb149cce6264e0abnd * by loading ocr->next before calling any maintenance function.
0d0ba3a410038e179b695446bb149cce6264e0abnd for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
205f749042ed530040a4f0080dbcb47ceae8a374rjung (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
0d0ba3a410038e179b695446bb149cce6264e0abnd /* XXX: um, well we've just wasted some space in pconf ? */
static void probe_writable_fds(void)
int fd_max;
int rc;
fd_max = 0;
if (fd_max == 0)
if (rc == 0)
int i, status;
int not_dead_yet;
#ifdef HAS_OTHER_CHILD
not_dead_yet = 0;
for (i = 0; i < max_daemons_limit; ++i) {
int pid;
++not_dead_yet;
switch (tries) {
pid);
pid);
#ifdef HAS_OTHER_CHILD
else if (waitret == 0) {
++not_dead_yet;
if (!not_dead_yet) {
#ifndef INTERVAL_OF_WRITABLE_PROBES
static int wait_or_timeout_counter;
int ret;
#ifdef HAS_OTHER_CHILD
if (ret > 0) {
return ret;
clean_child_exit(0);
static int volatile shutdown_pending;
static int volatile restart_pending;
static int volatile is_graceful;
void ap_start_shutdown(void)
#ifndef WIN32
static void set_signals(void)
#ifndef NO_USE_SIGACTION
if (!one_process) {
#if defined(SA_ONESHOT)
#ifdef SIGBUS
#ifdef SIGABORT
#ifdef 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
pid);
case SIGTERM:
case SIGHUP:
case SIGUSR1:
case SIGKILL:
#ifdef SYS_SIGLIST
#ifdef WCOREDUMP
#ifdef WCOREDUMP
int num_listeners = 0;
return num_listeners;
static void sock_disable_nagle(int s)
int ap_graceful_stop_signalled(void)
return is_graceful;
int csd;
conn_id);
static void *worker_thread(void *);
static int start_thread(void)
static int reported = 0;
if (!reported) {
static void check_pipe_of_death(void)
if (!workers_may_exit) {
int ret;
char pipe_read_char;
int srv;
while (!workers_may_exit) {
if (workers_may_exit) break;
if (!thread_just_started) {
thread_just_started = 0;
if (workers_may_exit) {
!= APR_SUCCESS) {
while (!workers_may_exit) {
if (srv < 0) {
if (workers_may_exit) break;
goto got_fd;
curr_pollfd++;
goto got_fd;
if (!workers_may_exit) {
!= APR_SUCCESS) {
if (!start_thread()) {
!= APR_SUCCESS) {
if (worker_thread_count == 0) {
return NULL;
int signal_received;
pchild));
if (unixd_setup_child()) {
worker_thread_count = 0;
for (i = 0; i < max_threads; i++) {
worker_thread_free_ids[i] = i;
for (i=0; i < threads_to_start; i++) {
if (!start_thread()) {
switch (signal_received) {
case SIGTERM:
case SIGINT:
int pid;
if (one_process) {
set_signals();
if (!pid) {
#ifdef AIX_BIND_PROCESSOR
return number_to_start;
#ifndef MAX_SPAWN_RATE
static int hold_off_on_exponential_spawning;
static void perform_child_maintenance(void)
int free_length;
free_length = 0;
for (i = 0; i < num_daemons; ++i) {
++free_length;
last_non_dead = i;
if (free_length > 0) {
for (i = 0; i < free_length; ++i) {
int child_slot;
int pid;
if (pid >= 0) {
for (i = 0; i < max_daemons_limit; ++i) {
child_slot = i;
for (j = 0; j < HARD_THREAD_LIMIT; j++) {
if (child_slot >= 0) {
#ifdef HAS_OTHER_CHILD
else if (is_graceful) {
else if (remaining_children_to_start) {
return APR_EBADF;
return APR_SUCCESS;
server_conf = s;
server_conf = s;
my_pid);
if (!is_graceful) {
if (!is_graceful) {
for (i = 0; i < HARD_SERVER_LIMIT; i++) {
set_signals();
if (!is_graceful) {
if (shutdown_pending) {
if (one_process) {
if (is_graceful) {
for (i = 0; i < num_daemons; ++i) {
for (i = 0; i < num_daemons;) {
static int restart_num = 0;
is_graceful = 0;
if (!one_process) {
unixd_detach();
static void dexter_hooks(void)
one_process = 0;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
return err;
if (min_spare_threads <= 0) {
return NULL;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
const char *fname;
return err;
return NULL;
{ NULL }