dexter.c revision 302dc1f7b3feee23a91ad8f3cf3cb2edd95a557b
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* ====================================================================
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Redistribution and use in source and binary forms, with or without
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * modification, are permitted provided that the following conditions
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * 1. Redistributions of source code must retain the above copyright
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * notice, this list of conditions and the following disclaimer.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * 2. Redistributions in binary form must reproduce the above copyright
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * notice, this list of conditions and the following disclaimer in
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * the documentation and/or other materials provided with the
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * distribution.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * 3. All advertising materials mentioning features or use of this
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * software must display the following acknowledgment:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * "This product includes software developed by the Apache Group
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * for use in the Apache HTTP server project (http://www.apache.org/)."
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * 4. The names "Apache Server" and "Apache Group" must not be used to
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * endorse or promote products derived from this software without
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * prior written permission. For written permission, please contact
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * apache@apache.org.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * 5. Products derived from this software may not be called "Apache"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * nor may "Apache" appear in their names without prior written
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * permission of the Apache Group.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * 6. Redistributions of any form whatsoever must retain the following
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * acknowledgment:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * "This product includes software developed by the Apache Group
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * for use in the Apache HTTP server project (http://www.apache.org/)."
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * OF THE POSSIBILITY OF SUCH DAMAGE.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * ====================================================================
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * This software consists of voluntary contributions made by many
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * individuals on behalf of the Apache Group and was originally based
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * on public domain software written at the National Center for
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Supercomputing Applications, University of Illinois, Urbana-Champaign.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * For more information on the Apache Group and the Apache HTTP server
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * project, please see <http://www.apache.org/>.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_config.h" /* for read_config */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_core.h" /* for get_remote_host */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Actual definitions of config globals
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int threads_to_start = 0; /* Worker threads per child */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Table of child status */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic struct {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan unsigned char status;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next != NULL) {stmt;}} while (0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SAFE_ACCEPT(stmt) do {stmt;} while (0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * The max child slot ever assigned, preserved across restarts. Necessary
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * to deal with NumServers changes across SIGWINCH restarts. We use this
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * value to optimize routines that have to scan the entire child table.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * XXX - It might not be worth keeping this code in. There aren't very
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * many child processes in this MPM.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic char ap_coredump_dir[MAX_STRING_LEN];
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t pipe_of_death_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* *Non*-shared http_main globals... */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* one_process --- debugging mode variable; can be set from the command line
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * with the -X flag. If set, this gets you the child_main loop running
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * in the process which originally started up (no detach, no make_child),
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * which is a pretty nice debugging environment. (You'll get a SIGHUP
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * early in standalone_main; just continue through. This is the server
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * trying to kill off any child processes which it might have lying
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * around --- Apache doesn't keep track of their pids, it just sends
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * SIGHUP to the process group, ignoring it in the root process.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Continue through and you'll be fine.).
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* used to maintain list of children which aren't part of the child table */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalantypedef struct other_child_rec other_child_rec;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan void (*maintenance) (int, void *, ap_wait_t);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic ap_context_t *pconf; /* Pool for config stuff */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic ap_context_t *pchild; /* Pool for httpd child stuff */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic ap_context_t *thread_pool_parent; /* Parent of per-thread pools */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t thread_pool_create_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int my_pid; /* Linux getpid() doesn't work except in main thread. Use
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan this instead */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Keep track of the number of worker threads currently active */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t worker_thread_count_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int worker_thread_free_ids[HARD_THREAD_LIMIT];
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Keep track of the number of idle worker threads */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t idle_thread_count_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Global, alas, so http_core can talk to us */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanenum server_token_type ap_server_tokens = SrvTk_FULL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki RajagopalanAPI_EXPORT(const server_rec *) ap_get_server_conf(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* a clean exit from a child with proper cleanup
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan static void ap_clean_child_exit(int code) __attribute__ ((noreturn)); */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * dealing with other children
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki RajagopalanAPI_EXPORT(void) ap_register_other_child(int pid,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan void (*maintenance) (int reason, void *, ap_wait_t status),
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* note that since this can be called by a maintenance function while we're
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * scanning the other_children list, all scanners should protect themself
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * by loading ocr->next before calling any maintenance function.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki RajagopalanAPI_EXPORT(void) ap_unregister_other_child(void *data)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX: um, well we've just wasted some space in pconf ? */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* test to ensure that the write_fds are all still writable, otherwise
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * invoke the maintenance functions as appropriate */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = ocr->next) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX: uhh this could be really bad, we could have a bad file
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * descriptor due to a bug in one of the maintenance routines */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_unixerr("probe_writable_fds", "select",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "could not probe writable fds", server_conf);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = nocr) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (FD_ISSET(ocr->write_fd, &writable_fds))
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* possibly reap an other_child, return 0 if yes, -1 if not */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int reap_other_child(int pid, ap_wait_t status)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = nocr) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void reclaim_child_processes(int terminate)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan long int waittime = 1024 * 16; /* in usecs */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* don't want to hold up progress any more than
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * necessary, but we need to allow children a few moments to exit.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Set delay with an exponential backoff.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* now see who is done */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (i = 0; i < max_daemons_limit; ++i) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* ok, now it's being annoying */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child process %d still did not exit, sending a SIGTERM",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* die child scum */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child process %d still did not exit, sending a SIGKILL",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* gave it our best shot, but alas... If this really
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * is a child we are trying to kill and it really hasn't
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * exited, we will likely fail to bind to the port
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * after the restart.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "could not make child process %d exit, "
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = nocr) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan waitret = waitpid(ocr->pid, &status, WNOHANG);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else if (waitret == 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* uh what the heck? they didn't call unregister? */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* nothing left to wait for */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Finally, this routine is used by the caretaker process to wait for
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* number of calls to wait_or_timeout between writable probes */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int wait_or_timeout(ap_wait_t *status)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* handle all varieties of core dumping signals */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* At this point we've got sig blocked, because we're still inside
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * the signal handler. When we leave the signal handler it will
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * be unblocked, and we'll take the signal... and coredump or whatever
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * is appropriate for this particular Unix. In addition the parent
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * will see the real signal we received -- whereas if we called
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * abort() here, the parent would only see SIGABRT.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Connection structures and accounting...
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* volatile just in case */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int volatile shutdown_pending;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int volatile restart_pending;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int volatile is_graceful;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * functions to initiate shutdown or restart without relying on signals.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Previously this was initiated in sig_term() and restart() signal handlers,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * but we want to be able to start a shutdown/restart from other sources --
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * e.g. on Win32, from the service manager. Now the service manager can
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * these functions can also be called by the child processes, since global
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * variables are no longer used to pass on the required action to the parent.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * These should only be called from the parent process itself, since the
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * parent process will use the shutdown_pending and restart_pending variables
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * to determine whether to shutdown or restart. The child process should
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * call signal_parent() directly to tell the parent to die -- this will
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * cause neither of those variable to be set, which the parent will
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * assume means something serious is wrong (which it will be, for the
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * child to force an exit) and so do an exit anyway.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* Um, is this _probably_ not an error, if the user has
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * tried to do a shutdown twice quickly, so we won't
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * worry about reporting it.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* do a graceful restart if graceful == 1 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* Probably not an error - don't bother reporting it */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void set_signals(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGILL)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* we want to ignore HUPs and WINCH while we're busy processing one */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGWINCH)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGBUS */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGABORT */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGABRT */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGILL */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGXCPU */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGXFSZ */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGHUP */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGWINCH */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGPIPE */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void process_child_status(int pid, ap_wait_t status)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* Child died... if it died due to a fatal error,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * we should simply bail out.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "Child %d returned a Fatal error... \n"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "Apache is exiting!",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child pid %d exit signal %s (%d), "
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "possible coredump in %s",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child pid %d exit signal %d",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ap_listen_open(s->process, s->port)) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (lr = ap_listeners; lr; lr = lr->next) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Here follows a long bunch of generic server bookkeeping stuff...
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void sock_disable_nagle(int s) /* ZZZ abstract */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* The Nagle algorithm says that we should delay sending partial
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * packets in hopes of getting more data. We don't want to do
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * this; we are not telnet. There are bad interactions between
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * persistent connections and Nagle's algorithm that have very severe
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * performance penalties. (Failing to disable Nagle is not much of a
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * problem with simple HTTP.)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * In spite of these problems, failure here is not a shooting offense.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sizeof(int)) < 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "setsockopt: (TCP_NODELAY)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX - Does this really work? - Manoj */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Child process main loop.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void process_socket(ap_context_t *p, struct sockaddr *sa_client, int csd,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (getsockname(csd, &sa_server, &len) < 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "filedescriptor (%u) larger than FD_SETSIZE (%u) "
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "found, you probably need to rebuild Apache with a "
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, NULL,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "error attaching to socket");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan current_conn = ap_new_connection(p, server_conf, conn_io,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void *worker_thread(void *);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Starts a thread as long as we're below max_threads */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (pthread_create(&thread, &worker_thread_attr, worker_thread,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan &worker_thread_free_ids[worker_thread_count])) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "pthread_create: unable to create worker thread");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* In case system resources are maxxed out, we don't want
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan Apache running away with the CPU trying to fork over and
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan over and over again if we exit. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan static int reported = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "server reached MaxThreadsPerChild setting, consider raising the"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan " MaxThreadsPerChild or NumServers settings");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Sets workers_may_exit if we received a character on the pipe_of_death */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ret = read(listenfds[0].fd, &pipe_read_char, 1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* It lost the lottery. It must continue to suffer
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * through a life of servitude. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* It won the lottery (or something else is very
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * wrong). Embrace death with open arms. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&pipe_of_death_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* idle_thread_count should be incremented before starting a worker_thread */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_context_t *tpool; /* Pool for this thread */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_context_t *ptrans; /* Pool for per-transaction stuff */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan long conn_id = child_num * HARD_THREAD_LIMIT + thread_num;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&thread_pool_create_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_create_context(&tpool, thread_pool_parent);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&thread_pool_create_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan workers_may_exit |= (max_requests_per_child != 0) && (requests_this_child <= 0);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (idle_thread_count < max_spare_threads) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan srv = poll(listenfds, num_listenfds + 1, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* poll() will only return errors in catastrophic
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * circumstances. Let's try exiting gracefully, for now. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_ERR, (const server_rec *)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* A process got a signal on the shutdown pipe. Check if we're
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * the lucky process to die. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* find a listener */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX: Should we check for POLLERR? */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (listenfds[curr_pollfd].revents & POLLIN) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_put_os_sock(&sd, &listenfds[curr_pollfd].fd, tpool);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (idle_thread_count > min_spare_threads) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan process_socket(ptrans, &sa_client, native_socket, conn_id);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan worker_thread_free_ids[worker_thread_count] = thread_num;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* All the threads have exited, now finish the shutdown process
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * by signalling the sigwait thread */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /*stuff to do before we switch id's, so we have permissions.*/
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(accept_mutex_child_init(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;
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;
const char *fname;
return err;
return NULL;
struct ap_thread_mutex {
return mtx;
{ NULL }