dexter.c revision 302dc1f7b3feee23a91ad8f3cf3cb2edd95a557b
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* ====================================================================
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan *
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 * are met:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define CORE_PRIVATE
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "apr_portable.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "httpd.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_main.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_log.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_config.h" /* for read_config */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_core.h" /* for get_remote_host */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "http_connection.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "ap_mpm.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "unixd.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "iol_socket.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "ap_listen.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "acceptlock.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "mpm_default.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "dexter.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include "scoreboard.h"
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include <poll.h>
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include <netinet/tcp.h>
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#include <pthread.h>
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Actual definitions of config globals
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int threads_to_start = 0; /* Worker threads per child */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int min_spare_threads = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int max_spare_threads = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int max_threads = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int max_requests_per_child = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic char *ap_pid_fname=NULL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int num_daemons=0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int workers_may_exit = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int requests_this_child;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int num_listenfds = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic struct pollfd *listenfds;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Table of child status */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SERVER_DEAD 0
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SERVER_DYING 1
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SERVER_ALIVE 2
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic struct {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pid_t pid;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan unsigned char status;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan} child_table[HARD_SERVER_LIMIT];
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#if 0
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next != NULL) {stmt;}} while (0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#else
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define SAFE_ACCEPT(stmt) do {stmt;} while (0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*
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 *
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 Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanint max_daemons_limit = -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic char ap_coredump_dir[MAX_STRING_LEN];
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int pipe_of_death[2];
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t pipe_of_death_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* *Non*-shared http_main globals... */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic server_rec *server_conf;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int one_process = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef DEBUG_SIGSTOP
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanint raise_sigstop_flags;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef HAS_OTHER_CHILD
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 Rajagopalanstruct other_child_rec {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_child_rec *next;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int pid;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan void (*maintenance) (int, void *, ap_wait_t);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan void *data;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int write_fd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan};
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic other_child_rec *other_children;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int child_num;
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 int worker_thread_count;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t worker_thread_count_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int worker_thread_free_ids[HARD_THREAD_LIMIT];
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_attr_t worker_thread_attr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Keep track of the number of idle worker threads */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int idle_thread_count;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic pthread_mutex_t idle_thread_count_mutex;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Global, alas, so http_core can talk to us */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanenum server_token_type ap_server_tokens = SrvTk_FULL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki RajagopalanAPI_EXPORT(const server_rec *) ap_get_server_conf(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return (server_conf);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* a clean exit from a child with proper cleanup
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan static void ap_clean_child_exit(int code) __attribute__ ((noreturn)); */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanvoid ap_clean_child_exit(int code)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (pchild) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_destroy_pool(pchild);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan exit(code);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * dealing with other children
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef HAS_OTHER_CHILD
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki RajagopalanAPI_EXPORT(void) ap_register_other_child(int pid,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan void (*maintenance) (int reason, void *, ap_wait_t status),
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan void *data, int write_fd)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_child_rec *ocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr = ap_palloc(pconf, sizeof(*ocr));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->pid = pid;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->maintenance = maintenance;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->data = data;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->write_fd = write_fd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->next = other_children;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_children = ocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki RajagopalanAPI_EXPORT(void) ap_unregister_other_child(void *data)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_child_rec **pocr, *nocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if ((*pocr)->data == data) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan nocr = (*pocr)->next;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan *pocr = nocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX: um, well we've just wasted some space in pconf ? */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* test to ensure that the write_fds are all still writable, otherwise
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * invoke the maintenance functions as appropriate */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void probe_writable_fds(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#if 0
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan fd_set writable_fds;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int fd_max;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_child_rec *ocr, *nocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan struct timeval tv;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int rc;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (other_children == NULL)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan fd_max = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan FD_ZERO(&writable_fds);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan do {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = ocr->next) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ocr->write_fd == -1)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan FD_SET(ocr->write_fd, &writable_fds);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ocr->write_fd > fd_max) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan fd_max = ocr->write_fd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (fd_max == 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_sec = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_usec = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan } while (rc == -1 && errno == EINTR);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (rc == -1) {
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 return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (rc == 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = nocr) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan nocr = ocr->next;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ocr->write_fd == -1)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (FD_ISSET(ocr->write_fd, &writable_fds))
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_child_rec *ocr, *nocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = nocr) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan nocr = ocr->next;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ocr->pid != pid)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->pid = -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void reclaim_child_processes(int terminate)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int i, status;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan long int waittime = 1024 * 16; /* in usecs */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan struct timeval tv;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int waitret, tries;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int not_dead_yet;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef HAS_OTHER_CHILD
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan other_child_rec *ocr, *nocr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_sec = waittime / 1000000;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_usec = waittime % 1000000;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan waittime = waittime * 4;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_select(0, NULL, NULL, NULL, &tv);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* now see who is done */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan not_dead_yet = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (i = 0; i < max_daemons_limit; ++i) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int pid;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (child_table[i].status == SERVER_DEAD)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pid = child_table[i].pid;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan waitret = waitpid(pid, &status, WNOHANG);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (waitret == pid || waitret == -1) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan child_table[i].status = SERVER_DEAD;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ++not_dead_yet;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan switch (tries) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 1: /* 16ms */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 2: /* 82ms */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 3: /* 344ms */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 4: /* 16ms */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 5: /* 82ms */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 6: /* 344ms */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 7: /* 1.4sec */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* ok, now it's being annoying */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child process %d still did not exit, sending a SIGTERM",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pid);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan kill(pid, SIGTERM);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 8: /* 6 sec */
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 pid);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan kill(pid, SIGKILL);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case 9: /* 14 sec */
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 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "could not make child process %d exit, "
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "attempting to continue anyway", pid);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef HAS_OTHER_CHILD
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (ocr = other_children; ocr; ocr = nocr) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan nocr = ocr->next;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ocr->pid == -1)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan waitret = waitpid(ocr->pid, &status, WNOHANG);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (waitret == ocr->pid) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->pid = -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else if (waitret == 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ++not_dead_yet;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else if (waitret == -1) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* uh what the heck? they didn't call unregister? */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ocr->pid = -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!not_dead_yet) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* nothing left to wait for */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Finally, this routine is used by the caretaker process to wait for
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * a while...
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* number of calls to wait_or_timeout between writable probes */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifndef INTERVAL_OF_WRITABLE_PROBES
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define INTERVAL_OF_WRITABLE_PROBES 10
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int wait_or_timeout_counter;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int wait_or_timeout(ap_wait_t *status)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan struct timeval tv;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int ret;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ++wait_or_timeout_counter;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan wait_or_timeout_counter = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef HAS_OTHER_CHILD
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan probe_writable_fds();
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ret = waitpid(-1, status, WNOHANG);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ret == -1 && errno == EINTR) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ret > 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return ret;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_select(0, NULL, NULL, NULL, &tv);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return -1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* handle all varieties of core dumping signals */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void sig_coredump(int sig)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan chdir(ap_coredump_dir);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(sig, SIG_DFL);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan kill(getpid(), sig);
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}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void just_die(int sig)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_clean_child_exit(0);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Connection structures and accounting...
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*
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 *
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 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void ap_start_shutdown(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (shutdown_pending == 1) {
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 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan shutdown_pending = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* do a graceful restart if graceful == 1 */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void ap_start_restart(int graceful)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (restart_pending == 1) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* Probably not an error - don't bother reporting it */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan restart_pending = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan is_graceful = graceful;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void sig_term(int sig)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_start_shutdown();
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void restart(int sig)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifndef WIN32
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_start_restart(sig == SIGWINCH);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#else
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_start_restart(1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void set_signals(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifndef NO_USE_SIGACTION
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan struct sigaction sa;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sigemptyset(&sa.sa_mask);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_flags = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!one_process) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_handler = sig_coredump;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#if defined(SA_ONESHOT)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_flags = SA_ONESHOT;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#elif defined(SA_RESETHAND)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_flags = SA_RESETHAND;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGSEGV, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGBUS
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGBUS, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGABORT
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGABORT, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGABRT
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGABRT, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGILL
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGILL, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGILL)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_flags = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_handler = sig_term;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGTERM, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGINT
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGINT, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGXCPU
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_handler = SIG_DFL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGXCPU, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGXFSZ
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_handler = SIG_DFL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGXFSZ, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGPIPE
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_handler = SIG_IGN;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGPIPE, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* we want to ignore HUPs and WINCH while we're busy processing one */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sigaddset(&sa.sa_mask, SIGHUP);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sigaddset(&sa.sa_mask, SIGWINCH);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sa.sa_handler = restart;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGHUP, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (sigaction(SIGWINCH, &sa, NULL) < 0)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGWINCH)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#else
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!one_process) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGSEGV, sig_coredump);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGBUS
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGBUS, sig_coredump);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGBUS */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGABORT
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGABORT, sig_coredump);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGABORT */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGABRT
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGABRT, sig_coredump);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGABRT */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGILL
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGILL, sig_coredump);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGILL */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGXCPU
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGXCPU, SIG_DFL);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGXCPU */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGXFSZ
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGXFSZ, SIG_DFL);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGXFSZ */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGTERM, sig_term);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGHUP
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGHUP, restart);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGHUP */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGWINCH
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGWINCH, restart);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGWINCH */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SIGPIPE
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan signal(SIGPIPE, SIG_IGN);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif /* SIGPIPE */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void process_child_status(int pid, ap_wait_t status)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* Child died... if it died due to a fatal error,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * we should simply bail out.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if ((WIFEXITED(status)) &&
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 pid);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan exit(APEXIT_CHILDFATAL);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (WIFSIGNALED(status)) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan switch (WTERMSIG(status)) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case SIGTERM:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case SIGHUP:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case SIGUSR1:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan case SIGKILL:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan default:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef SYS_SIGLIST
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef WCOREDUMP
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (WCOREDUMP(status)) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child pid %d exit signal %s (%d), "
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "possible coredump in %s",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pid, (WTERMSIG(status) >= NumSIG) ? "" :
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_coredump_dir);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child pid %d exit signal %s (%d)", pid,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#ifdef WCOREDUMP
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#else
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan server_conf,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "child pid %d exit signal %d",
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pid, WTERMSIG(status));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int setup_listeners(server_rec *s)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_listen_rec *lr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int num_listeners = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ap_listen_open(s->process, s->port)) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan for (lr = ap_listeners; lr; lr = lr->next) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan num_listeners++;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return num_listeners;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Here follows a long bunch of generic server bookkeeping stuff...
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void sock_disable_nagle(int s) /* ZZZ abstract */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
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 *
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * In spite of these problems, failure here is not a shooting offense.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int just_say_no = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#else
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#define sock_disable_nagle(s) /* NOOP */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan#endif
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanint ap_graceful_stop_signalled(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX - Does this really work? - Manoj */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return is_graceful;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/*****************************************************************
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * Child process main loop.
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void process_socket(ap_context_t *p, struct sockaddr *sa_client, int csd,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int conn_id)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan struct sockaddr sa_server; /* ZZZZ */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan NET_SIZE_T len = sizeof(struct sockaddr);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan BUFF *conn_io;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan conn_rec *current_conn;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_iol *iol;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (getsockname(csd, &sa_server, &len) < 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan close(csd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sock_disable_nagle(csd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan iol = unix_attach_socket(csd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (iol == NULL) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (errno == EBADF) {
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 "larger FD_SETSIZE", csd, FD_SETSIZE);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_log_error(APLOG_MARK, APLOG_WARNING, NULL,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan "error attaching to socket");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan close(csd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan conn_io = ap_bcreate(p, B_RDWR);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_bpush_iol(conn_io, iol);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan current_conn = ap_new_connection(p, server_conf, conn_io,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (const struct sockaddr_in *) sa_client,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan (const struct sockaddr_in *) &sa_server,
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan conn_id);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_process_connection(current_conn);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void *worker_thread(void *);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Starts a thread as long as we're below max_threads */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic int start_thread(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_t thread;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (worker_thread_count < max_threads) {
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 sleep(10);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan workers_may_exit = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan worker_thread_count++;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan static int reported = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!reported) {
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 reported = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* Sets workers_may_exit if we received a character on the pipe_of_death */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void check_pipe_of_death(void)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&pipe_of_death_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!workers_may_exit) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int ret;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan char pipe_read_char;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ret = read(listenfds[0].fd, &pipe_read_char, 1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (ret == -1 && errno == EAGAIN) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* It lost the lottery. It must continue to suffer
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * through a life of servitude. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* It won the lottery (or something else is very
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * wrong). Embrace death with open arms. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan workers_may_exit = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&pipe_of_death_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan/* idle_thread_count should be incremented before starting a worker_thread */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void *worker_thread(void *arg)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan struct sockaddr sa_client;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_socket_t *csd = NULL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_context_t *tpool; /* Pool for this thread */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_context_t *ptrans; /* Pool for per-transaction stuff */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_socket_t *sd = NULL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int srv;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int curr_pollfd, last_pollfd = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int thread_just_started = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int thread_num = *((int *) arg);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan long conn_id = child_num * HARD_THREAD_LIMIT + thread_num;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int native_socket;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 ap_create_context(&ptrans, tpool);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan while (!workers_may_exit) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan workers_may_exit |= (max_requests_per_child != 0) && (requests_this_child <= 0);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (workers_may_exit) break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!thread_just_started) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (idle_thread_count < max_spare_threads) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan idle_thread_count++;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan thread_just_started = 0;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(intra_mutex_on(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (workers_may_exit) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(intra_mutex_off(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(accept_mutex_on(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan while (!workers_may_exit) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan srv = poll(listenfds, num_listenfds + 1, -1);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (srv < 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (errno == EINTR) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
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 ap_get_server_conf(), "poll: (listen)");
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan workers_may_exit = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (workers_may_exit) break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (listenfds[0].revents & POLLIN) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* A process got a signal on the shutdown pipe. Check if we're
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * the lucky process to die. */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan check_pipe_of_death();
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan continue;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (num_listenfds == 1) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sd = ap_listeners->sd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan goto got_fd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* find a listener */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan curr_pollfd = last_pollfd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan do {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan curr_pollfd++;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (curr_pollfd > num_listenfds) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan curr_pollfd = 1;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* XXX: Should we check for POLLERR? */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (listenfds[curr_pollfd].revents & POLLIN) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan last_pollfd = curr_pollfd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_put_os_sock(&sd, &listenfds[curr_pollfd].fd, tpool);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan goto got_fd;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan } while (curr_pollfd != last_pollfd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan got_fd:
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!workers_may_exit) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_accept(&csd, sd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(accept_mutex_off(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(intra_mutex_off(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (idle_thread_count > min_spare_threads) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan idle_thread_count--;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (!start_thread()) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan idle_thread_count--;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan } else {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(accept_mutex_off(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(intra_mutex_off(0));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan idle_thread_count--;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&idle_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan break;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_get_os_sock(&native_socket, csd);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan process_socket(ptrans, &sa_client, native_socket, conn_id);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_clear_pool(ptrans);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan requests_this_child--;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_destroy_pool(tpool);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_lock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan worker_thread_count--;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan worker_thread_free_ids[worker_thread_count] = thread_num;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan if (worker_thread_count == 0) {
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /* All the threads have exited, now finish the shutdown process
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan * by signalling the sigwait thread */
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan kill(my_pid, SIGTERM);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan }
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan pthread_mutex_unlock(&worker_thread_count_mutex);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan return NULL;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan}
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalanstatic void child_main(int child_num_arg)
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan{
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan sigset_t sig_mask;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int signal_received;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan int i;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_listen_rec *lr;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan my_pid = getpid();
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan child_num = child_num_arg;
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan ap_create_context(&pchild, pconf);
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan /*stuff to do before we switch id's, so we have permissions.*/
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(intra_mutex_init(pchild, 1));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan SAFE_ACCEPT(accept_mutex_child_init(pchild));
b494511a9cf72b1fc4eb13a0e593f55c624ab829Venki Rajagopalan
if (unixd_setup_child()) {
ap_clean_child_exit(APEXIT_CHILDFATAL);
}
ap_child_init_hook(pchild, server_conf);
/*done with init critical section */
/* All threads should mask signals out, accoring to sigwait(2) man page */
sigfillset(&sig_mask);
if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL) != 0) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, "pthread_sigmask");
}
requests_this_child = max_requests_per_child;
/* Set up the pollfd array */
listenfds = ap_palloc(pchild, sizeof(struct pollfd) * (num_listenfds + 1));
listenfds[0].fd = pipe_of_death[0];
listenfds[0].events = POLLIN;
listenfds[0].revents = 0;
for (lr = ap_listeners, i = 1; i <= num_listenfds; lr = lr->next, ++i) {
ap_get_os_sock(&listenfds[i].fd, lr->sd);
listenfds[i].events = POLLIN; /* should we add POLLPRI ?*/
listenfds[i].revents = 0;
}
/* Setup worker threads */
if (threads_to_start > max_threads) {
threads_to_start = max_threads;
}
idle_thread_count = threads_to_start;
worker_thread_count = 0;
for (i = 0; i < max_threads; i++) {
worker_thread_free_ids[i] = i;
}
ap_create_context(&thread_pool_parent, pchild);
pthread_mutex_init(&thread_pool_create_mutex, NULL);
pthread_mutex_init(&idle_thread_count_mutex, NULL);
pthread_mutex_init(&worker_thread_count_mutex, NULL);
pthread_mutex_init(&pipe_of_death_mutex, NULL);
pthread_attr_init(&worker_thread_attr);
pthread_attr_setdetachstate(&worker_thread_attr, PTHREAD_CREATE_DETACHED);
/* We are creating worker threads right now */
for (i=0; i < threads_to_start; i++) {
/* start_thread shouldn't fail here */
if (!start_thread()) {
break;
}
}
/* This thread will be the one responsible for handling signals */
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGTERM);
sigaddset(&sig_mask, SIGINT);
sigwait(&sig_mask, &signal_received);
switch (signal_received) {
case SIGTERM:
case SIGINT:
just_die(signal_received);
break;
default:
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
"received impossible signal: %d", signal_received);
just_die(SIGTERM);
}
}
static int make_child(server_rec *s, int slot, time_t now) /* ZZZ */
{
int pid;
if (slot + 1 > max_daemons_limit) {
max_daemons_limit = slot + 1;
}
if (one_process) {
set_signals();
child_table[slot].pid = getpid();
child_table[slot].status = SERVER_ALIVE;
child_main(slot);
}
if ((pid = fork()) == -1) {
ap_log_error(APLOG_MARK, APLOG_ERR, s, "fork: Unable to fork new process");
/* In case system resources are maxxed out, we don't want
Apache running away with the CPU trying to fork over and
over and over again. */
sleep(10);
return -1;
}
if (!pid) {
#ifdef AIX_BIND_PROCESSOR
/* By default, AIX binds to a single processor. This bit unbinds
children which will then bind to another CPU.
*/
#include <sys/processor.h>
int status = bindprocessor(BINDPROCESS, (int)getpid(),
PROCESSOR_CLASS_ANY);
if (status != OK)
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
"processor unbind failed %d", status);
#endif
RAISE_SIGSTOP(MAKE_CHILD);
/* XXX - For an unthreaded server, a signal handler will be necessary
signal(SIGTERM, just_die);
*/
child_main(slot);
return 0;
}
/* else */
child_table[slot].pid = pid;
child_table[slot].status = SERVER_ALIVE;
return 0;
}
/* start up a bunch of children */
static int startup_children(int number_to_start)
{
int i;
for (i = 0; number_to_start && i < num_daemons; ++i) {
if (child_table[i].status != SERVER_DEAD) {
continue;
}
if (make_child(server_conf, i, 0) < 0) {
break;
}
--number_to_start;
}
return number_to_start;
}
/*
* spawn_rate is the number of children that will be spawned on the
* next maintenance cycle if there aren't enough servers. It is
* doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
* without the need to spawn.
*/
static int spawn_rate = 1;
#ifndef MAX_SPAWN_RATE
#define MAX_SPAWN_RATE (32)
#endif
static int hold_off_on_exponential_spawning;
static void perform_child_maintenance(void)
{
int i;
time_t now = 0;
int free_length;
int free_slots[MAX_SPAWN_RATE];
int last_non_dead = -1;
/* initialize the free_list */
free_length = 0;
ap_check_signals();
for (i = 0; i < num_daemons; ++i) {
if (child_table[i].status == SERVER_DEAD) {
if (free_length < spawn_rate) {
free_slots[free_length] = i;
++free_length;
}
}
else {
last_non_dead = i;
}
if (i >= max_daemons_limit && free_length >= spawn_rate) {
break;
}
}
max_daemons_limit = last_non_dead + 1;
if (free_length > 0) {
for (i = 0; i < free_length; ++i) {
make_child(server_conf, free_slots[i], now);
}
/* 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;
}
else if (spawn_rate < MAX_SPAWN_RATE) {
spawn_rate *= 2;
}
}
else {
spawn_rate = 1;
}
}
static void server_main_loop(int remaining_children_to_start)
{
int child_slot;
ap_wait_t status;
int pid;
int i;
while (!restart_pending && !shutdown_pending) {
pid = wait_or_timeout(&status);
if (pid >= 0) {
process_child_status(pid, status);
/* non-fatal death... note that it's gone in the child table and
* clean out the status table. */
child_slot = -1;
for (i = 0; i < max_daemons_limit; ++i) {
if (child_table[i].pid == pid) {
int j;
child_slot = i;
for (j = 0; j < HARD_THREAD_LIMIT; j++) {
ap_reset_connection_status(i * HARD_THREAD_LIMIT + j);
}
break;
}
}
if (child_slot >= 0) {
child_table[child_slot].status = SERVER_DEAD;
if (remaining_children_to_start
&& child_slot < num_daemons) {
/* we're still doing a 1-for-1 replacement of dead
* children with new children
*/
/* ZZZ abstract out for AP funcs. */
make_child(server_conf, child_slot, time(NULL));
--remaining_children_to_start;
}
#ifdef HAS_OTHER_CHILD
}
else if (reap_other_child(pid, status) == 0) {
/* handled */
#endif
}
else if (is_graceful) {
/* Great, we've probably just lost a slot in the
* child table. Somehow we don't know about this
* child.
*/
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
"long lost child came home! (pid %d)", pid);
}
/* Don't perform idle maintenance when a child dies,
* only do it when there's a timeout. Remember only a
* finite number of children can die, and it's pretty
* pathological for a lot to die suddenly.
*/
continue;
}
else if (remaining_children_to_start) {
/* we hit a 1 second timeout in which none of the previous
* generation of children needed to be reaped... so assume
* they're all done, and pick up the slack if any is left.
*/
remaining_children_to_start = \
startup_children(remaining_children_to_start);
/* In any event we really shouldn't do the code below because
* few of the servers we just started are in the IDLE state
* yet, so we'd mistakenly create an extra server.
*/
continue;
}
perform_child_maintenance();
}
}
static ap_status_t cleanup_fd(void *fdptr)
{
if (close(*((int *) fdptr)) < 0) {
return APR_EBADF;
}
return APR_SUCCESS;
}
int ap_mpm_run(ap_context_t *_pconf, ap_context_t *plog, server_rec *s)
{
int remaining_children_to_start;
int i;
pconf = _pconf;
server_conf = s;
if (pipe(pipe_of_death) == -1) {
ap_log_error(APLOG_MARK, APLOG_ERR,
(const server_rec*) server_conf,
"pipe: (pipe_of_death)");
exit(1);
}
ap_register_cleanup(pconf, &pipe_of_death[0], cleanup_fd, cleanup_fd);
ap_register_cleanup(pconf, &pipe_of_death[1], cleanup_fd, cleanup_fd);
if (fcntl(pipe_of_death[0], F_SETFD, O_NONBLOCK) == -1) {
ap_log_error(APLOG_MARK, APLOG_ERR,
(const server_rec*) server_conf,
"fcntl: O_NONBLOCKing (pipe_of_death)");
exit(1);
}
server_conf = s;
if ((num_listenfds = setup_listeners(server_conf)) < 1) {
/* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, s,
"no listening sockets available, shutting down");
return 1;
}
ap_log_pid(pconf, ap_pid_fname);
SAFE_ACCEPT(accept_mutex_init(pconf, 1));
if (!is_graceful) {
reinit_scoreboard(pconf);
}
/* Initialize the child table */
if (!is_graceful) {
for (i = 0; i < HARD_SERVER_LIMIT; i++) {
child_table[i].status = SERVER_DEAD;
}
}
set_signals();
/* If we're doing a graceful_restart then we're going to see a lot
* of children exiting immediately when we get into the main loop
* below (because we just sent them SIGWINCH). This happens pretty
* rapidly... and for each one that exits we'll start a new one until
* we reach at least daemons_min_free. But we may be permitted to
* start more than that, so we'll just keep track of how many we're
* supposed to start up without the 1 second penalty between each fork.
*/
remaining_children_to_start = num_daemons;
if (!is_graceful) {
remaining_children_to_start = \
startup_children(remaining_children_to_start);
}
else {
/* give the system some time to recover before kicking into
* exponential mode */
hold_off_on_exponential_spawning = 10;
}
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
"%s configured -- resuming normal operations",
ap_get_server_version());
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
"Server built: %s", ap_get_server_built());
restart_pending = shutdown_pending = 0;
server_main_loop(remaining_children_to_start);
if (shutdown_pending) {
/* Time to gracefully shut down:
* Kill child processes, tell them to call child_exit, etc...
*/
if (ap_killpg(getpgrp(), SIGTERM) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
}
reclaim_child_processes(1); /* Start with SIGTERM */
/* 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_NOERRNO|APLOG_INFO,
server_conf,
"removed PID file %s (pid=%ld)",
pidfile, (long)getpid());
}
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
"caught SIGTERM, shutting down");
return 1;
}
/* we've been told to restart */
signal(SIGHUP, SIG_IGN);
if (one_process) {
/* not worth thinking about */
return 1;
}
if (is_graceful) {
char char_of_death = '!';
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
"SIGWINCH received. Doing graceful restart");
/* This is mostly for debugging... so that we know what is still
* gracefully dealing with existing request.
*/
for (i = 0; i < num_daemons; ++i) {
if (child_table[i].status != SERVER_DEAD) {
child_table[i].status = SERVER_DYING;
}
}
/* give the children the signal to die */
for (i = 0; i < num_daemons;) {
if (write(pipe_of_death[1], &char_of_death, 1) == -1) {
if (errno == EINTR) continue;
ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "write pipe_of_death");
}
i++;
}
}
else {
/* Kill 'em all. Since the child acts the same on the parents SIGTERM
* and a SIGHUP, we may as well use the same signal, because some user
* pthreads are stealing signals from us left and right.
*/
if (ap_killpg(getpgrp(), SIGTERM) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
}
reclaim_child_processes(1); /* Start with SIGTERM */
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
"SIGHUP received. Attempting to restart");
}
return 0;
}
static void dexter_pre_config(ap_context_t *p, ap_context_t *plog, ap_context_t *ptemp)
{
static int restart_num = 0;
one_process = !!getenv("ONE_PROCESS");
/* sigh, want this only the second time around */
if (restart_num++ == 1) {
is_graceful = 0;
if (!one_process) {
unixd_detach();
}
my_pid = getpid();
}
unixd_pre_config();
ap_listen_pre_config();
num_daemons = DEFAULT_NUM_DAEMON;
threads_to_start = DEFAULT_START_THREAD;
min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
max_threads = HARD_THREAD_LIMIT;
ap_pid_fname = DEFAULT_PIDLOG;
ap_lock_fname = DEFAULT_LOCKFILE;
max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
}
static void dexter_hooks(void)
{
ap_hook_pre_config(dexter_pre_config, NULL, NULL, HOOK_MIDDLE);
INIT_SIGLIST()
one_process = 0;
}
static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
if (cmd->server->is_virtual) {
return "PidFile directive not allowed in <VirtualHost>";
}
ap_pid_fname = arg;
return NULL;
}
static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
ap_lock_fname = arg;
return NULL;
}
static const char *set_num_daemons (cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
num_daemons = atoi(arg);
if (num_daemons > HARD_SERVER_LIMIT) {
fprintf(stderr, "WARNING: NumServers of %d exceeds compile time limit "
"of %d servers,\n", num_daemons, HARD_SERVER_LIMIT);
fprintf(stderr, " lowering NumServers to %d. To increase, please "
"see the\n", HARD_SERVER_LIMIT);
fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
num_daemons = HARD_SERVER_LIMIT;
}
else if (num_daemons < 1) {
fprintf(stderr, "WARNING: Require NumServers > 0, setting to 1\n");
num_daemons = 1;
}
return NULL;
}
static const char *set_threads_to_start (cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
threads_to_start = atoi(arg);
if (threads_to_start > HARD_THREAD_LIMIT) {
fprintf(stderr, "WARNING: StartThreads of %d exceeds compile time"
"limit of %d threads,\n", threads_to_start,
HARD_THREAD_LIMIT);
fprintf(stderr, " lowering StartThreads to %d. To increase, please"
"see the\n", HARD_THREAD_LIMIT);
fprintf(stderr, " HARD_THREAD_LIMIT define in src/include/httpd.h.\n");
}
else if (threads_to_start < 1) {
fprintf(stderr, "WARNING: Require StartThreads > 0, setting to 1\n");
threads_to_start = 1;
}
return NULL;
}
static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
min_spare_threads = atoi(arg);
if (min_spare_threads <= 0) {
fprintf(stderr, "WARNING: detected MinSpareThreads set to non-positive.\n");
fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
fprintf(stderr, "Please read the documentation.\n");
min_spare_threads = 1;
}
return NULL;
}
static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
max_spare_threads = atoi(arg);
if (max_spare_threads >= HARD_THREAD_LIMIT) {
fprintf(stderr, "WARNING: detected MinSpareThreads set higher than\n");
fprintf(stderr, "HARD_THREAD_LIMIT. Resetting to %d\n", HARD_THREAD_LIMIT);
max_spare_threads = HARD_THREAD_LIMIT;
}
return NULL;
}
static const char *set_max_threads(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
max_threads = atoi(arg);
if (max_threads > HARD_THREAD_LIMIT) {
fprintf(stderr, "WARNING: detected MaxThreadsPerChild set higher than\n");
fprintf(stderr, "HARD_THREAD_LIMIT. Resetting to %d\n", HARD_THREAD_LIMIT);
max_threads = HARD_THREAD_LIMIT;
}
return NULL;
}
static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
max_requests_per_child = atoi(arg);
return NULL;
}
static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg)
{
struct stat finfo;
const char *fname;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
fname = ap_server_root_relative(cmd->pool, arg);
/* ZZZ change this to the AP func FileInfo*/
if ((stat(fname, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
" does not exist or is not a directory", NULL);
}
ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
return NULL;
}
struct ap_thread_mutex {
pthread_mutex_t mutex;
};
API_EXPORT(ap_thread_mutex *) ap_thread_mutex_new(void)
{
ap_thread_mutex *mtx;
mtx = malloc(sizeof(ap_thread_mutex));
pthread_mutex_init(&(mtx->mutex), NULL);
return mtx;
}
API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
{
/* Ignoring error conditions here. :( */
pthread_mutex_lock(&(mtx->mutex));
}
API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
{
/* Here too. */
pthread_mutex_unlock(&(mtx->mutex));
}
API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
{
/* Here too. */
pthread_mutex_destroy(&(mtx->mutex));
free(mtx);
}
static const command_rec dexter_cmds[] = {
UNIX_DAEMON_COMMANDS
LISTEN_COMMANDS
{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
"A file for logging the server process ID"},
{ "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1,
"The lockfile used when Apache needs to lock the accept() call"},
{ "NumServers", set_num_daemons, NULL, RSRC_CONF, TAKE1,
"Number of children alive at the same time" },
{ "StartThreads", set_threads_to_start, NULL, RSRC_CONF, TAKE1,
"Number of threads each child creates" },
{ "MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, TAKE1,
"Minimum number of idle threads per child, to handle request spikes" },
{ "MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, TAKE1,
"Maximum number of idle threads per child" },
{ "MaxThreadsPerChild", set_max_threads, NULL, RSRC_CONF, TAKE1,
"Maximum number of threads per child" },
{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
"Maximum number of requests a particular child serves before dying." },
{ "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
"The location of the directory Apache changes to before dumping core" },
{ NULL }
};
module MODULE_VAR_EXPORT mpm_dexter_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
dexter_cmds, /* command ap_table_t */
NULL, /* handlers */
dexter_hooks /* register_hooks */
};