leader.c revision 2d399cd7535887fceaa9f8f116eb98ce68ddd602
e1e8390280254f7f0580d701e583f670643d4f3fnilgun/* ====================================================================
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * The Apache Software License, Version 1.1
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * reserved.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Redistribution and use in source and binary forms, with or without
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * modification, are permitted provided that the following conditions
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 1. Redistributions of source code must retain the above copyright
2e545ce2450a9953665f701bb05350f0d3f26275nd * notice, this list of conditions and the following disclaimer.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 2. Redistributions in binary form must reproduce the above copyright
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * notice, this list of conditions and the following disclaimer in
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * the documentation and/or other materials provided with the
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * distribution.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * 3. The end-user documentation included with the redistribution,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * if any, must include the following acknowledgment:
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * "This product includes software developed by the
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Apache Software Foundation (http://www.apache.org/)."
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Alternately, this acknowledgment may appear in the software itself,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * if and wherever such third-party acknowledgments normally appear.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * 4. The names "Apache" and "Apache Software Foundation" must
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * not be used to endorse or promote products derived from this
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * software without prior written permission. For written
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * permission, please contact apache@apache.org.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * 5. Products derived from this software may not be called "Apache",
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic * nor may "Apache" appear in their name, without prior written
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * permission of the Apache Software Foundation.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * SUCH DAMAGE.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * ====================================================================
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun * This software consists of voluntary contributions made by many
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * individuals on behalf of the Apache Software Foundation. For more
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * information on the Apache Software Foundation, please see
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * Portions of this software are based upon public domain software
2704de98885368683621b01c8f8f4e4b01557611takashi * originally written at the National Center for Supercomputing Applications,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * University of Illinois, Urbana-Champaign.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun/* The purpose of this MPM is to fix the design flaws in the threaded
c38e2a97e43fc69b22f6b03c6d2f60e3bd705f89sf * model. Because of the way that pthreads and mutex locks interact,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * it is basically impossible to cleanly gracefully shutdown a child
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * process if multiple threads are all blocked in accept. This model
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * fixes those problems.
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun#error The Leader/Follower MPM requires APR threads, but they are unavailable.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun/* Limit on the total --- clients will be locked out if more servers than
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * this are needed. It is intended solely to keep the server from crashing
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * when things get out of hand.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * We keep a hard maximum number of servers, for two reasons --- first off,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * in case something goes seriously wrong, we want to stop the fork bomb
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun * short of actually crashing the machine we're running on by filling some
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun * kernel table. Secondly, it keeps the size of the scoreboard file small
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * enough that we can read the whole thing without worrying too much about
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * the overhead.
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun * some sort of compile-time limit to help catch typos.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun/* Limit on the threads per process. Clients will be locked out if more than
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * this * server_limit are needed.
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun * We keep this for one reason it keeps the size of the scoreboard file small
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * enough that we can read the whole thing without worrying too much about
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * the overhead.
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun * some sort of compile-time limit to help catch typos.
2704de98885368683621b01c8f8f4e4b01557611takashi * Actual definitions of config globals
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgunint ap_threads_per_child = 0; /* Worker threads per child */
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic int min_spare_threads = 0;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgunstatic int max_spare_threads = 0;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgunstatic int ap_daemons_limit = 0;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgunstatic int dying = 0;
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic int workers_may_exit = 0;
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic int num_listensocks = 0;
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic int resource_shortage = 0;
0d0ba3a410038e179b695446bb149cce6264e0abnd/* The structure used to pass unique initialization info to each thread */
727872d18412fc021f03969b8641810d8896820bhumbedoohtypedef struct {
0d0ba3a410038e179b695446bb149cce6264e0abnd/* Structure used to pass information to the thread responsible for
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh * creating the rest of the threads.
0d0ba3a410038e179b695446bb149cce6264e0abndtypedef struct {
07dc96d063d49299da433f84b5c5681da9bbdf68rbowen#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * The max child slot ever assigned, preserved across restarts. Necessary
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * use this value to optimize routines that have to scan the entire
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * scoreboard.
static int one_process = 0;
#ifdef DEBUG_SIGSTOP
int raise_sigstop_flags;
struct worker_wakeup_info {
return NULL;
return NULL;
return wakeup;
int no_listener;
int terminated;
} worker_stack;
return NULL;
sizeof(worker_wakeup_info *));
return stack;
return rv;
return APR_EINVAL;
return rv;
return APR_SUCCESS;
return APR_ENOSPC;
return rv;
APR_SUCCESS) {
return rv;
return APR_SUCCESS;
return rv;
return rv;
return rv;
return rv;
return rv;
return rv;
return APR_SUCCESS;
return rv;
return rv;
return rv;
return rv;
return rv;
return APR_SUCCESS;
#define ST_INIT 0
switch(query_code){
case AP_MPMQ_MAX_DAEMON_USED:
return APR_SUCCESS;
case AP_MPMQ_IS_THREADED:
return APR_SUCCESS;
case AP_MPMQ_IS_FORKED:
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
case AP_MPMQ_MAX_THREADS:
return APR_SUCCESS;
*result = 0;
return APR_SUCCESS;
return APR_SUCCESS;
*result = 0;
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
case AP_MPMQ_MAX_DAEMONS:
return APR_SUCCESS;
return APR_ENOTIMPL;
if (pchild) {
0, ap_server_conf,
clean_child_exit(0);
static int volatile shutdown_pending;
static int volatile restart_pending;
static int volatile is_graceful;
static volatile int child_fatal;
static void ap_start_shutdown(void)
static void set_signals(void)
#ifndef NO_USE_SIGACTION
if (!one_process) {
#if defined(SA_ONESHOT)
#ifdef SIGBUS
#ifdef SIGABORT
#ifdef SIGABRT
#ifdef SIGILL
#ifdef SIGINT
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGPIPE
if (!one_process) {
#ifdef SIGBUS
#ifdef SIGABORT
#ifdef SIGABRT
#ifdef SIGILL
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGHUP
#ifdef AP_SIG_GRACEFUL
#ifdef SIGPIPE
int ap_graceful_stop_signalled(void)
return workers_may_exit;
int csd;
if (current_conn) {
static void check_infinite_requests(void)
if (ap_max_requests_per_child) {
#if defined(SIGPROCMASK_SETS_THREAD_MASK)
int is_listener;
is_listener = 0;
while (!workers_may_exit) {
if (!is_listener) {
APR_SUCCESS) {
if (workers_may_exit) {
if (requests_this_child <= 0) {
if (workers_may_exit) break;
!= APR_SUCCESS) {
if (workers_may_exit) {
while (!workers_may_exit) {
if (workers_may_exit) break;
goto got_fd;
if (!workers_may_exit) {
!= APR_SUCCESS) {
if (workers_may_exit) {
is_listener = 0;
!= APR_SUCCESS) {
return NULL;
switch (signum) {
case SIGTERM:
case SIGINT:
int threads_created = 0;
int loops;
int prev_threads_created;
for (i = 0; i < ap_threads_per_child; i++) {
++loops;
return NULL;
for (i = 0; i < ap_threads_per_child; i++) {
pchild));
if (unixd_setup_child()) {
if (ap_max_requests_per_child) {
if (one_process) {
switch(terminate_mode) {
case ST_GRACEFUL:
case ST_UNGRACEFUL:
int pid;
if (one_process) {
set_signals();
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
clean_child_exit(0);
#ifndef MAX_SPAWN_RATE
static int hold_off_on_exponential_spawning;
static void perform_idle_server_maintenance(void)
int idle_thread_count;
int free_length;
int totally_free_length = 0;
int last_non_dead;
int total_non_dead;
free_length = 0;
idle_thread_count = 0;
total_non_dead = 0;
for (i = 0; i < ap_daemons_limit; ++i) {
int any_dying_threads = 0;
int any_dead_threads = 0;
for (j = 0; j < ap_threads_per_child; j++) {
if (all_dead_threads) {
++free_length;
if (!any_dying_threads) {
last_non_dead = i;
if (free_length == 0) {
static int reported = 0;
if (!reported) {
"or Min/MaxSpareThreads), "
for (i = 0; i < free_length; ++i) {
int child_slot;
if (child_slot >= 0) {
for (i = 0; i < ap_threads_per_child; i++)
else if (remaining_children_to_start
else if (is_graceful) {
else if (remaining_children_to_start) {
if (changed_limit_at_restart) {
if (!is_graceful) {
set_signals();
if (!is_graceful) {
if (shutdown_pending) {
if (!child_fatal) {
if (one_process) {
if (is_graceful) {
/* wake up the children...time to die. But we'll have more soon */
pconf = p;
ap_server_conf = s;
return DONE;
if (!one_process) {
return DONE;
return OK;
static int restart_num = 0;
if (!max_clients) {
else if (!max_clients
if (debug) {
no_detach = 0;
is_graceful = 0;
return HTTP_INTERNAL_SERVER_ERROR;
ap_extended_status = 0;
return OK;
one_process = 0;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
if (min_spare_threads <= 0) {
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
int max_clients;
return err;
return NULL;
const char *arg)
return err;
return NULL;
int tmp_server_limit;
return err;
if (first_server_limit &&
return NULL;
return NULL;
int tmp_thread_limit;
return err;
if (first_thread_limit &&
return NULL;
return NULL;
{ NULL }