event.c revision 1c6ad6ae62510775d157ee70085e1d735ff847e2
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim/* Licensed to the Apache Software Foundation (ASF) under one or more
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * contributor license agreements. See the NOTICE file distributed with
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * this work for additional information regarding copyright ownership.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * The ASF licenses this file to You under the Apache License, Version 2.0
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * (the "License"); you may not use this file except in compliance with
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * the License. You may obtain a copy of the License at
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * Unless required by applicable law or agreed to in writing, software
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * distributed under the License is distributed on an "AS IS" BASIS,
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * See the License for the specific language governing permissions and
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * limitations under the License.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * This MPM tries to fix the 'keep alive problem' in HTTP.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * After a client completes the first request, the client can keep the
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * connection open to send more requests with the same socket. This can save
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * significant overhead in creating TCP connections. However, the major
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * disadvantage is that Apache traditionally keeps an entire child
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * process/thread waiting for data from the client. To solve this problem,
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * this MPM has a dedicated thread for handling both the Listening sockets,
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * and all sockets that are in a Keep Alive status.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * The MPM assumes the underlying apr_pollset implementation is somewhat
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * threadsafe. This currently is only compatible with KQueue and EPoll. This
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * enables the MPM to avoid extra high level locking or having to wake up the
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * listener thread when a keep-alive socket needs to be sent to it.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * This MPM does not perform well on older platforms that do not have very good
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * threading, like Linux with a 2.4 kernel, but this does not matter, since we
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * require EPoll or KQueue.
0c32a43de97332a10a45ca4213339132dd4a3844trawick * For FreeBSD, use 5.3. It is possible to run this MPM on FreeBSD 5.2.1, if
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * you use libkse (see `man libmap.conf`).
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * For NetBSD, use at least 2.0.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * For Linux, you should use a 2.6 kernel, and make sure your glibc has epoll
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * support compiled in.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim#error The Event MPM requires APR threads, but they are unavailable.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim/* Limit on the total --- clients will be locked out if more servers than
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * this are needed. It is intended solely to keep the server from crashing
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * when things get out of hand.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * We keep a hard maximum number of servers, for two reasons --- first off,
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * in case something goes seriously wrong, we want to stop the fork bomb
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * short of actually crashing the machine we're running on by filling some
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * kernel table. Secondly, it keeps the size of the scoreboard file small
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * enough that we can read the whole thing without worrying too much about
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * the overhead.
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
67139e2d50d1e11558d87f7042f61cb04bb0d1d2jim * some sort of compile-time limit to help catch typos.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* Limit on the threads per process. Clients will be locked out if more than
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * this are needed.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * We keep this for one reason it keeps the size of the scoreboard file small
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * enough that we can read the whole thing without worrying too much about
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * the overhead.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * some sort of compile-time limit to help catch typos.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * Actual definitions of config globals
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick#define WORKER_FACTOR_SCALE 16 /* scale factor to allow fractional values */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic unsigned int worker_factor = DEFAULT_WORKER_FACTOR * WORKER_FACTOR_SCALE;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int threads_per_child = 0; /* Worker threads per child */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int min_spare_threads = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int max_spare_threads = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int ap_daemons_limit = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int max_workers = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int server_limit = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int thread_limit = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int had_healthy_child = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int dying = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int workers_may_exit = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int listener_may_exit = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int num_listensocks = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_int32_t conns_this_child; /* MaxConnectionsPerChild, only access
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick in listener thread */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_uint32_t connection_count = 0; /* Number of open connections */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_uint32_t lingering_count = 0; /* Number of connections in lingering close */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_uint32_t suspended_count = 0; /* Number of suspended connections */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_uint32_t clogged_count = 0; /* Number of threads processing ssl conns */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int resource_shortage = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** APR_RING of expiration timeouts */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** the expiration time of the next keepalive timeout */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** connection record this struct refers to */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** memory pool to allocate from */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** bucket allocator */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** poll file descriptor information */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /** public parts of the connection state */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick const char *tag;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * Several timeout queues that use different timeouts, so that we always can
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * simply append to the end.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * write_completion_q uses TimeOut
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * keepalive_q uses KeepAliveTimeOut
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * linger_q uses MAX_SECS_TO_LINGER
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * short_linger_q uses SECONDS_TO_LINGER
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic struct timeout_queue write_completion_q, keepalive_q, linger_q,
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * Macros for accessing struct timeout_queue.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * For TO_QUEUE_APPEND and TO_QUEUE_REMOVE, timeout_mutex must be held.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick APR_RING_INSERT_TAIL(&(q).head, el, event_conn_state_t, timeout_list); \
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick } while (0)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick } while (0)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick APR_RING_INIT(&(q).head, event_conn_state_t, timeout_list); \
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick (q).tag = #q; \
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick } while (0)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick#define TO_QUEUE_ELEM_INIT(el) APR_RING_ELEM_INIT(el, timeout_list)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * The pollset for sockets that are in any of the timeout queues. Currently
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * we use the timeout_mutex to make sure that connections are added/removed
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * atomically to/from both event_pollset and a timeout queue. Otherwise
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * some confusion can happen under high load if timeout queues and pollset
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * get out of sync.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * XXX: It should be possible to make the lock unnecessary in many or even all
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * XXX: cases.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef struct {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* The structure used to pass unique initialization info to each thread */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef struct
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* Structure used to pass information to the thread responsible for
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * creating the rest of the threads.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef struct
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef enum
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef struct
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef struct
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* data retained by event across load/unload of the module
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * allocated on first call to pre-config hook; located on
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * subsequent calls to pre-config hook
11f2c481e1d57bedb3f758565307501e9a2730ddtrawicktypedef struct event_retained_data {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick int volatile is_graceful; /* set from signal handler */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * The max child slot ever assigned, preserved across restarts. Necessary
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * We use this value to optimize routines that have to scan the entire
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * scoreboard.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * idle_spawn_rate is the number of children that will be spawned on the
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * next maintenance cycle if there aren't enough idle servers. It is
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * without the need to spawn.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* The event MPM respects a couple of runtime flags that can aid
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * in debugging. Setting the -DNO_DETACH flag will prevent the root process
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * from detaching from its controlling terminal. Additionally, setting
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * child_main loop running in the process which originally started up.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * early in standalone_main; just continue through. This is the server
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * trying to kill off any child processes which it might have lying
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * around --- Apache doesn't keep track of their pids, it just sends
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * SIGHUP to the process group, ignoring it in the root process.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * Continue through and you'll be fine.).
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic int one_process = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_pool_t *pconf; /* Pool for config stuff */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick thread. Use this instead */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* The LISTENER_SIGNAL signal will be sent from the main thread to the
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * listener thread to wake it up for graceful termination (what a child
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * process from an old generation does when the admin does "apachectl
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * graceful"). This signal will be blocked in all threads of a child
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * process except for the listener thread.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick/* An array of socket descriptors in use by each thread used to
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * perform a non-graceful (forced) shutdown of the server.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick for (i = 0; i < num_listensocks; i++) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick apr_pollset_remove(event_pollset, &listener_pollfd[i]);
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick ap_scoreboard_image->parent[process_slot].not_accepting = 1;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00457)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick "Accepting new connections again: "
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick "%u active conns (%u lingering/%u clogged/%u suspended), "
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick "%u idle workers",
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick for (i = 0; i < num_listensocks; i++)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick apr_pollset_add(event_pollset, &listener_pollfd[i]);
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * XXX: This is not yet optimal. If many workers suddenly become available,
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * XXX: the parent may kill some processes off too soon.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick ap_scoreboard_image->parent[process_slot].not_accepting = 0;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic void close_worker_sockets(void)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick for (i = 0; i < threads_per_child; i++) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawickstatic void wakeup_listener(void)
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /* XXX there is an obscure path that this doesn't handle perfectly:
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * right after listener thread is created but before
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * listener_os_thread is set, the first worker thread hits an
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * error and starts graceful termination
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /* unblock the listener if it's waiting for a worker */
#ifdef HAVE_PTHREAD_KILL
#define ST_INIT 0
switch (query_code) {
case AP_MPMQ_MAX_DAEMON_USED:
case AP_MPMQ_IS_THREADED:
case AP_MPMQ_IS_FORKED:
case AP_MPMQ_IS_ASYNC:
case AP_MPMQ_HAS_SERF:
case AP_MPMQ_MAX_THREADS:
*result = 0;
*result = 0;
case AP_MPMQ_MAX_DAEMONS:
case AP_MPMQ_MPM_STATE:
case AP_MPMQ_GENERATION:
return OK;
static const char *event_get_name(void)
if (pchild) {
if (one_process) {
clean_child_exit(0);
static int child_fatal;
static int volatile shutdown_pending;
static int volatile restart_pending;
case CONN_STATE_LINGER_NORMAL:
case CONN_STATE_LINGER_SHORT:
case CONN_STATE_SUSPENDED:
return APR_SUCCESS;
static void set_signals(void)
#ifndef NO_USE_SIGACTION
if (!one_process) {
#ifndef NO_USE_SIGACTION
#ifdef AP_SIG_GRACEFUL_STOP
#ifdef SIGINT
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGPIPE
if (!one_process) {
#ifdef SIGXCPU
#ifdef SIGXFSZ
#ifdef SIGHUP
#ifdef AP_SIG_GRACEFUL
#ifdef AP_SIG_GRACEFUL_STOP
#ifdef SIGPIPE
struct timeout_queue *q;
#ifdef AP_DEBUG
q = &short_linger_q;
q = &linger_q;
if (c->aborted
AP_DEBUG_ASSERT(0);
int my_thread_num)
conn_rec *c;
int rc;
apr_pool_clear(p);
cs->c = c;
cs->p = p;
c = cs->c;
if (!c->aborted) {
* fall thru to either wait for readability/timeout or
else if (c->data_in_output_filters) {
else if (c->data_in_input_filters) {
goto read_request;
apr_time_now();
static void check_infinite_requests(void)
if (ap_max_requests_per_child) {
if (!*closed) {
for (i = 0; i < threads_per_child; ++i) {
#if defined(SIGPROCMASK_SETS_THREAD_MASK)
#if HAVE_SERF
void *serf_baton)
void *serf_baton)
#if HAVE_SERF
#if HAVE_SERF
s_socket_remove, p);
return APR_SUCCESS;
return rc;
if (*have_idle_worker_p) {
if (blocking)
static int indexing_comp(void *a, void *b)
void *baton)
return APR_SUCCESS;
apr_pool_t *p,
int for_read,
void *baton)
int i = 0, nsock;
while(s[i] != NULL) {
nsock = i;
for (i = 0; i<nsock; i++) {
return final_rc;
int i = 0, nsock;
while(s[i] != NULL) {
nsock = i;
for (i = 0; i<nsock; i++) {
return final_rc;
struct timeout_queue *q;
int count = 0;
if (!q->count) {
count++;
if (!count)
while (count) {
count--;
int have_idle_worker = 0;
return NULL;
int workers_were_busy = 0;
if (listener_may_exit) {
if (conns_this_child <= 0)
if (te) {
#if HAVE_SERF
if (listener_may_exit) {
while (ep) {
while (num) {
blocking = 0;
if (!have_idle_worker) {
have_idle_worker = 0;
case CONN_STATE_LINGER_NORMAL:
case CONN_STATE_LINGER_SHORT:
ap_assert(0);
if (workers_were_busy) {
if (!listeners_disabled)
if (!listeners_disabled)
else if (listeners_disabled) {
listeners_disabled = 0;
if (!listeners_disabled) {
return NULL;
have_idle_worker = 0;
#if HAVE_SERF
out_pfd++;
num--;
listeners_disabled = 0;
return NULL;
/* XXX For ungraceful termination/restart, we definitely don't want to
int is_idle = 0;
while (!workers_may_exit) {
if (!is_idle) {
if (workers_may_exit) {
goto worker_pop;
else if (!workers_may_exit) {
is_idle = 0;
return NULL;
switch (signum) {
case SIGTERM:
case SIGINT:
int threads_created = 0;
int listener_started = 0;
int loops;
int prev_threads_created;
pchild);
for (i = 0; i < sizeof(good_methods) / sizeof(void*); i++) {
good_methods[i]);
* sizeof(apr_socket_t *));
for (i = 0; i < threads_per_child; i++) {
int status =
++loops;
return NULL;
if (listener) {
int iter;
iter = 0;
++iter;
for (i = 0; i < threads_per_child; i++) {
if (ap_max_requests_per_child) {
if (ap_thread_stacksize != 0) {
if (one_process) {
switch (terminate_mode) {
case ST_GRACEFUL:
case ST_UNGRACEFUL:
int pid;
if (one_process) {
set_signals();
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
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;
int active_thread_count = 0;
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;
int child_threads_active = 0;
for (j = 0; j < threads_per_child; j++) {
if (any_dead_threads
if (all_dead_threads) {
++free_length;
if (!any_dying_threads) {
last_non_dead = i;
if (had_healthy_child) {
"or Min/MaxSpareThreads), "
for (i = 0; i < free_length; ++i) {
int child_slot;
if (child_slot < 0
if (child_slot >= 0) {
for (i = 0; i < threads_per_child; i++)
else if (remaining_children_to_start
status) == 0) {
else if (remaining_children_to_start) {
return DONE;
set_signals();
if (!child_fatal) {
return DONE;
} else if (shutdown_pending) {
int active_children;
int index;
if (!child_fatal) {
if (ap_graceful_shutdown_timeout) {
shutdown_pending = 0;
active_children = 0;
return DONE;
if (one_process) {
return DONE;
/* wake up the children...time to die. But we'll have more soon */
return OK;
int startup = 0;
int level_flags = 0;
pconf = p;
return DONE;
if (!one_process) {
return DONE;
return OK;
if (debug) {
no_detach = 0;
if (!retained) {
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
had_healthy_child = 0;
ap_extended_status = 0;
return OK;
int startup = 0;
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (ap_daemons_to_start < 0) {
if (startup) {
if (startup) {
return OK;
one_process = 0;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
double val;
char *endptr;
return err;
if (*endptr)
if (val <= 0)
if (worker_factor == 0)
return NULL;
{NULL}