eventopt.c revision 0cb18804f6760c3803a42718671de6aa0e971936
08cb74ca432a8c24e39f17dedce527e6a47b8001jerenkrantz/* Licensed to the Apache Software Foundation (ASF) under one or more
08cb74ca432a8c24e39f17dedce527e6a47b8001jerenkrantz * contributor license agreements. See the NOTICE file distributed with
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * this work for additional information regarding copyright ownership.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * The ASF licenses this file to You under the Apache License, Version 2.0
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * (the "License"); you may not use this file except in compliance with
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * the License. You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This MPM tries to fix the 'keep alive problem' in HTTP.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * After a client completes the first request, the client can keep the
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein * connection open to send more requests with the same socket. This can save
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * significant overhead in creating TCP connections. However, the major
8a46775d163c06a8c51d1b0a3f2edfde945cb1d8stoddard * disadvantage is that Apache traditionally keeps an entire child
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley * process/thread waiting for data from the client. To solve this problem,
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein * this MPM has a dedicated thread for handling both the Listening sockets,
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein * and all sockets that are in a Keep Alive status.
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein * The MPM assumes the underlying apr_pollset implementation is somewhat
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein * threadsafe. This currently is only compatible with KQueue and EPoll. This
f4c310fd2555c6faca1f980f00b161eadb089023gstein * enables the MPM to avoid extra high level locking or having to wake up the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener thread when a keep-alive socket needs to be sent to it.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This MPM does not perform well on older platforms that do not have very good
f4c310fd2555c6faca1f980f00b161eadb089023gstein * threading, like Linux with a 2.4 kernel, but this does not matter, since we
1a9d922232824a7cc008d4f74e48bd82adf5bdedgstein * require EPoll or KQueue.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * For FreeBSD, use 5.3. It is possible to run this MPM on FreeBSD 5.2.1, if
f4c310fd2555c6faca1f980f00b161eadb089023gstein * you use libkse (see `man libmap.conf`).
f4c310fd2555c6faca1f980f00b161eadb089023gstein * For NetBSD, use at least 2.0.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * For Linux, you should use a 2.6 kernel, and make sure your glibc has epoll
f4c310fd2555c6faca1f980f00b161eadb089023gstein * support compiled in.
707ecf9559338ec06b24334bc9abcca670325cc4gstein#error The EventOpt MPM requires APR threads, but they are unavailable.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Limit on the total --- clients will be locked out if more servers than
f4c310fd2555c6faca1f980f00b161eadb089023gstein * this are needed. It is intended solely to keep the server from crashing
f4c310fd2555c6faca1f980f00b161eadb089023gstein * when things get out of hand.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * We keep a hard maximum number of servers, for two reasons --- first off,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in case something goes seriously wrong, we want to stop the fork bomb
f4c310fd2555c6faca1f980f00b161eadb089023gstein * short of actually crashing the machine we're running on by filling some
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * kernel table. Secondly, it keeps the size of the scoreboard file small
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * enough that we can read the whole thing without worrying too much about
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the overhead.
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * some sort of compile-time limit to help catch typos.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Limit on the threads per process. Clients will be locked out if more than
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * this are needed.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * We keep this for one reason it keeps the size of the scoreboard file small
f4c310fd2555c6faca1f980f00b161eadb089023gstein * enough that we can read the whole thing without worrying too much about
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * the overhead.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * some sort of compile-time limit to help catch typos.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * Actual definitions of config globals
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define WORKER_FACTOR_SCALE 16 /* scale factor to allow fractional values */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic unsigned int worker_factor = DEFAULT_WORKER_FACTOR * WORKER_FACTOR_SCALE;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int threads_per_child = 0; /* Worker threads per child */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int min_spare_threads = 0;
0b1895a2cd5b4a9450709abdb7ae9974908f9382gsteinstatic int max_spare_threads = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int ap_daemons_limit = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int max_workers = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int server_limit = 0;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int thread_limit = 0;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int had_healthy_child = 0;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int dying = 0;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int workers_may_exit = 0;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int listener_may_exit = 0;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int num_listensocks = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_int32_t conns_this_child; /* MaxConnectionsPerChild, only access
f4c310fd2555c6faca1f980f00b161eadb089023gstein in listener thread */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_uint32_t connection_count = 0; /* Number of open connections */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic apr_uint32_t lingering_count = 0; /* Number of connections in lingering close */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic apr_uint32_t suspended_count = 0; /* Number of suspended connections */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_uint32_t clogged_count = 0; /* Number of threads processing ssl conns */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int resource_shortage = 0;
9ec6440fdeb81f04905959293b381ebbfa3114c2jortontypedef enum {
707ecf9559338ec06b24334bc9abcca670325cc4gstein /** APR_RING of expiration timeouts */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** the expiration time of the next keepalive timeout */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** connection record this struct refers to */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /** memory pool to allocate from */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** bucket allocator */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** poll file descriptor information */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** public parts of the connection state */
cc8241a7ee9815575a267e13eff62b6fddf1fe58gsteintypedef struct pollset_op_t {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *tag;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *tag;
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Several timeout queues that use different timeouts, so that we always can
49bf4df23d9e5281abcd83005550bda818b17b08wrowe * simply append to the end.
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * write_completion_q uses TimeOut
f4c310fd2555c6faca1f980f00b161eadb089023gstein * keepalive_q uses KeepAliveTimeOut
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * linger_q uses MAX_SECS_TO_LINGER
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * short_linger_q uses SECONDS_TO_LINGER
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowestatic struct timeout_queue write_completion_q, keepalive_q, linger_q,
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * Macros for accessing struct timeout_queue.
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * For TO_QUEUE_APPEND and TO_QUEUE_REMOVE, timeout_mutex must be held.
e8f95a682820a599fe41b22977010636be5c2717jim APR_RING_INSERT_TAIL(&(q).head, el, event_conn_state_t, timeout_list); \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe } while (0)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe } while (0)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe APR_RING_INIT(&(q).head, event_conn_state_t, timeout_list); \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe (q).tag = #q; \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe } while (0)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe#define TO_QUEUE_ELEM_INIT(el) APR_RING_ELEM_INIT(el, timeout_list)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein * The pollset for sockets that are in any of the timeout queues. Currently
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we use the timeout_mutex to make sure that connections are added/removed
f4c310fd2555c6faca1f980f00b161eadb089023gstein * atomically to/from both event_pollset and a timeout queue. Otherwise
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein * some confusion can happen under high load if timeout queues and pollset
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein * get out of sync.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: It should be possible to make the lock unnecessary in many or even all
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: cases.
01e8aca9299a0b872414c24c8b7724d6f88ae665ianhtypedef struct {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/* The structure used to pass unique initialization info to each thread */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowetypedef struct
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Structure used to pass information to the thread responsible for
f4c310fd2555c6faca1f980f00b161eadb089023gstein * creating the rest of the threads.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowetypedef struct
7f69a90d847f08a86f9909c2c5129408697a9600jortontypedef enum
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct
7f69a90d847f08a86f9909c2c5129408697a9600jorton/* data retained by event across load/unload of the module
f4c310fd2555c6faca1f980f00b161eadb089023gstein * allocated on first call to pre-config hook; located on
f4c310fd2555c6faca1f980f00b161eadb089023gstein * subsequent calls to pre-config hook
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct event_retained_data {
7f69a90d847f08a86f9909c2c5129408697a9600jorton int volatile is_graceful; /* set from signal handler */
7f69a90d847f08a86f9909c2c5129408697a9600jorton * The max child slot ever assigned, preserved across restarts. Necessary
7f69a90d847f08a86f9909c2c5129408697a9600jorton * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts.
7f69a90d847f08a86f9909c2c5129408697a9600jorton * We use this value to optimize routines that have to scan the entire
7f69a90d847f08a86f9909c2c5129408697a9600jorton * scoreboard.
7f69a90d847f08a86f9909c2c5129408697a9600jorton * idle_spawn_rate is the number of children that will be spawned on the
7f69a90d847f08a86f9909c2c5129408697a9600jorton * next maintenance cycle if there aren't enough idle servers. It is
f4c310fd2555c6faca1f980f00b161eadb089023gstein * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
f4c310fd2555c6faca1f980f00b161eadb089023gstein * without the need to spawn.
7f69a90d847f08a86f9909c2c5129408697a9600jorton#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int *bucket; /* bucket array for the httpd child processes */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* The eventopt MPM respects a couple of runtime flags that can aid
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in debugging. Setting the -DNO_DETACH flag will prevent the root process
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * from detaching from its controlling terminal. Additionally, setting
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * child_main loop running in the process which originally started up.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * early in standalone_main; just continue through. This is the server
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * trying to kill off any child processes which it might have lying
e8f95a682820a599fe41b22977010636be5c2717jim * around --- Apache doesn't keep track of their pids, it just sends
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * SIGHUP to the process group, ignoring it in the root process.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Continue through and you'll be fine.).
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int one_process = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_pool_t *pchild; /* Pool for httpd child stuff */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
f4c310fd2555c6faca1f980f00b161eadb089023gstein thread. Use this instead */
7ac747af0cf476c2276aaf9999425e1b52bf5f64jorton/* The LISTENER_SIGNAL signal will be sent from the main thread to the
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton * listener thread to wake it up for graceful termination (what a child
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton * process from an old generation does when the admin does "apachectl
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * graceful"). This signal will be blocked in all threads of a child
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * process except for the listener thread.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* An array of socket descriptors in use by each thread used to
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * perform a non-graceful (forced) shutdown of the server.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (i = 0; i < num_listensocks; i++) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pollset_remove(event_pollset, &listener_pollfd[i]);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[process_slot].not_accepting = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00457)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Accepting new connections again: "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "%u active conns (%u lingering/%u clogged/%u suspended), "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "%u idle workers",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (i = 0; i < num_listensocks; i++)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: This is not yet optimal. If many workers suddenly become available,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * XXX: the parent may kill some processes off too soon.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_scoreboard_image->parent[process_slot].not_accepting = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void close_worker_sockets(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void wakeup_listener(void)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* XXX there is an obscure path that this doesn't handle perfectly:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * right after listener thread is created but before
4c449c30215bd5e8bad122a4118f5a7b0e995472wrowe * listener_os_thread is set, the first worker thread hits an
f4c310fd2555c6faca1f980f00b161eadb089023gstein * error and starts graceful termination
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* unblock the listener if it's waiting for a worker */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
f4c310fd2555c6faca1f980f00b161eadb089023gstein * platforms and wake up the listener thread since it is the only thread
f4c310fd2555c6faca1f980f00b161eadb089023gstein * with SIGHUP unblocked, but that doesn't work on Linux
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* in case we weren't called from the listener thread, wake up the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener thread
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* for ungraceful termination, let the workers exit now;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * for graceful termination, the listener thread will notify the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * workers to exit once it has stopped accepting new connections
f4c310fd2555c6faca1f980f00b161eadb089023gstein close_worker_sockets(); /* forcefully kill all current connections */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int event_query(int query_code, int *result, apr_status_t *rv)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void event_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (childnum != -1) { /* child had a scoreboard slot? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void event_note_child_started(int slot, pid_t pid)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gsteinstatic void event_note_child_lost_slot(int slot, pid_t newpid)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00458)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
da9adab0554faf94f8cc2705c2363aceacf75c46gstein /* Don't forget about this exiting child process, or we
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * won't be able to kill it if it doesn't exit by the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * time the server is shut down.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic const char *event_get_name(void)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return "eventopt";
da9adab0554faf94f8cc2705c2363aceacf75c46gstein/* a clean exit from a child with proper cleanup */
da9adab0554faf94f8cc2705c2363aceacf75c46gsteinstatic void clean_child_exit(int code) __attribute__ ((noreturn));
f39230a531b23d94f86a087963299bbe2e431a4agstein/*****************************************************************
f39230a531b23d94f86a087963299bbe2e431a4agstein * Connection structures and accounting...
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* volatile because they're updated from a signal handler */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int volatile shutdown_pending;
49bf4df23d9e5281abcd83005550bda818b17b08wrowestatic int volatile restart_pending;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t decrement_connection_count(void *cs_)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
f4c310fd2555c6faca1f980f00b161eadb089023gstein * functions to initiate shutdown or restart without relying on signals.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Previously this was initiated in sig_term() and restart() signal handlers,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * but we want to be able to start a shutdown/restart from other sources --
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * e.g. on Win32, from the service manager. Now the service manager can
f4c310fd2555c6faca1f980f00b161eadb089023gstein * call ap_start_shutdown() or ap_start_restart() as appropriate. Note that
f4c310fd2555c6faca1f980f00b161eadb089023gstein * these functions can also be called by the child processes, since global
f4c310fd2555c6faca1f980f00b161eadb089023gstein * variables are no longer used to pass on the required action to the parent.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * These should only be called from the parent process itself, since the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * parent process will use the shutdown_pending and restart_pending variables
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to determine whether to shutdown or restart. The child process should
f4c310fd2555c6faca1f980f00b161eadb089023gstein * call signal_parent() directly to tell the parent to die -- this will
f4c310fd2555c6faca1f980f00b161eadb089023gstein * cause neither of those variable to be set, which the parent will
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * assume means something serious is wrong (which it will be, for the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * child to force an exit) and so do an exit anyway.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Um, is this _probably_ not an error, if the user has
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * tried to do a shutdown twice quickly, so we won't
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * worry about reporting it.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* do a graceful restart if graceful == 1 */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Probably not an error - don't bother reporting it */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void set_signals(void)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00459)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein "sigaction(SIGTERM)");
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00460)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00461)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe "sigaction(SIGINT)");
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00462)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein "sigaction(SIGXCPU)");
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein /* For systems following the LFS standard, ignoring SIGXFSZ allows
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein * a write() beyond the 2GB limit to fail gracefully with E2BIG
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe * rather than terminate the process. */
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00463)
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe "sigaction(SIGXFSZ)");
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00464)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGPIPE)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
f4c310fd2555c6faca1f980f00b161eadb089023gstein * processing one */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00465)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGHUP)");
e8f95a682820a599fe41b22977010636be5c2717jim ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00466)
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGXCPU */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGXFSZ */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGHUP */
2dc8d653749bc319011afe9b02434c80a815d175trawick#endif /* AP_SIG_GRACEFUL */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* AP_SIG_GRACEFUL_STOP */
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein#endif /* SIGPIPE */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) {
49bf4df23d9e5281abcd83005550bda818b17b08wrowe ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(00467)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * close our side of the connection
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Pre-condition: cs is not in any timeout queue and not in the pollset,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * timeout_mutex is not locked
f4c310fd2555c6faca1f980f00b161eadb089023gstein * return: 0 if connection is fully closed,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * 1 if connection is lingering
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * may be called by listener or by worker thread.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the eq may be null if called from the listener thread,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * and the pollset operations are done directly by this function.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic int start_lingering_close(event_conn_state_t *cs, ap_equeue_t *eq)
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * If some module requested a shortened waiting period, only wait for
f4c310fd2555c6faca1f980f00b161eadb089023gstein * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain
f4c310fd2555c6faca1f980f00b161eadb089023gstein * DoS attacks.
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (apr_table_get(cs->c->notes, "short-lingering-close")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_now() + apr_time_from_sec(SECONDS_TO_LINGER);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_now() + apr_time_from_sec(MAX_SECS_TO_LINGER);
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT :
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Close our side of the connection, flushing data to the client first.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Pre-condition: cs is not in any timeout queue and not in the pollset,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * timeout_mutex is not locked
f4c310fd2555c6faca1f980f00b161eadb089023gstein * return: 0 if connection is fully closed,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * 1 if connection is lingering
f4c310fd2555c6faca1f980f00b161eadb089023gstein * May only be called by worker thread.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic int start_lingering_close_blocking(event_conn_state_t *cs, ap_equeue_t *eq)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Close our side of the connection, NOT flushing data to the client.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This should only be called if there has been an error or if we know
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * that our send buffers are empty.
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * Pre-condition: cs is not in any timeout queue and not in the pollset,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * timeout_mutex is not locked
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * return: 0 if connection is fully closed,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * 1 if connection is lingering
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * may be called by listener thread
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int start_lingering_close_nonblocking(event_conn_state_t *cs, ap_equeue_t *eq)
f4c310fd2555c6faca1f980f00b161eadb089023gstein || apr_socket_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein * forcibly close a lingering connection after the lingering period has
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Pre-condition: cs is not in any timeout queue and not in the pollset
f4c310fd2555c6faca1f980f00b161eadb089023gstein * return: irrelevant (need same prototype as start_lingering_close)
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int stop_lingering_close(event_conn_state_t *cs, ap_equeue_t *eq)
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "socket reached timeout in lingering-close state");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(00468) "error closing socket");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * process one connection in the worker
b6c56e35c5ebdbe1da09806714fb579f3b8c648egsteinstatic void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * sock,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley listener_poll_type *pt = apr_pcalloc(p, sizeof(*pt));
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein c = ap_run_create_connection(p, ap_server_conf, sock,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_pool_cleanup_register(c->pool, cs, decrement_connection_count,
33397e35239f202a595837571561468f02b2e806gstein ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(00469)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "process_socket: connection aborted");
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton * XXX If the platform does not have a usable way of bundling
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton * accept() with a socket readability check, like Win32,
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton * and there are measurable delays before the
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * socket is readable due to the first data packet arriving,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * it might be better to create the cs on the listener thread
33397e35239f202a595837571561468f02b2e806gstein * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE
f4c310fd2555c6faca1f980f00b161eadb089023gstein * FreeBSD users will want to enable the HTTP accept filter
f4c310fd2555c6faca1f980f00b161eadb089023gstein * module in their kernel for the highest performance
f4c310fd2555c6faca1f980f00b161eadb089023gstein * When the accept filter is active, sockets are kept in the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * kernel until a HTTP request is received.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Since we have an input filter which 'clogs' the input stream,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * like mod_ssl used to, lets just do the normal read from input
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * filters, like the Worker MPM does. Filters that need to write
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * where they would otherwise read, or read where they would
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * otherwise write, should set the sense appropriately.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* state will be updated upon return
e8f95a682820a599fe41b22977010636be5c2717jim * fall thru to either wait for readability/timeout or
e8f95a682820a599fe41b22977010636be5c2717jim * do lingering close
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = output_filter->frec->filter_func.out_func(output_filter, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "network write failure in core output filter");
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* Still in WRITE_COMPLETION_STATE:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Set a write timeout for this connection, and let the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * event thread poll for writeability.
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->expiration_time = ap_server_conf->timeout + apr_time_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
707ecf9559338ec06b24334bc9abcca670325cc4gstein else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* It greatly simplifies the logic to use a single timeout value here
707ecf9559338ec06b24334bc9abcca670325cc4gstein * because the new element can just be added to the end of the list and
f4c310fd2555c6faca1f980f00b161eadb089023gstein * it will stay sorted in expiration time sequence. If brand new
f4c310fd2555c6faca1f980f00b161eadb089023gstein * sockets are sent to the event thread for a readability check, this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * will be a slight behavior change - they use the non-keepalive
f4c310fd2555c6faca1f980f00b161eadb089023gstein * timeout today. With a normal client, the socket will be readable in
707ecf9559338ec06b24334bc9abcca670325cc4gstein * a few milliseconds anyway.
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->expiration_time = ap_server_conf->keep_alive_timeout +
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Add work to pollset. */
e8f95a682820a599fe41b22977010636be5c2717jim * Prevent this connection from writing to our connection state after it
f4c310fd2555c6faca1f980f00b161eadb089023gstein * is no longer associated with this thread. This would happen if the EOR
f4c310fd2555c6faca1f980f00b161eadb089023gstein * bucket is destroyed from the listener thread due to a connection abort
f4c310fd2555c6faca1f980f00b161eadb089023gstein * or timeout.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* conns_this_child has gone to zero or below. See if the admin coded
f4c310fd2555c6faca1f980f00b161eadb089023gstein "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way
f4c310fd2555c6faca1f980f00b161eadb089023gstein simplifies the hot path in worker_thread */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void check_infinite_requests(void)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Stopping process due to MaxConnectionsPerChild");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* keep going */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void close_listeners(int process_slot, int *closed) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[process_slot].quiescing = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < threads_per_child; ++i) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* wake up the main thread */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * then we don't need this goofy function.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* XXXXX: recycle listener_poll_types */
f4c310fd2555c6faca1f980f00b161eadb089023gstein listener_pollfd = apr_palloc(p, sizeof(apr_pollfd_t) * num_listensocks);
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (lr = child_listen; lr != NULL; lr = lr->next, i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* TODO: subpools, threads, reuse, etc. -- currently use malloc() inside :( */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t push_timer2worker(timer_event_t* te)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Pre-condition: pfd->cs is neither in pollset nor timeout queue
f4c310fd2555c6faca1f980f00b161eadb089023gstein * this function may only be called by the listener
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_status_t push2worker(const apr_pollfd_t * pfd,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe listener_poll_type *pt = (listener_poll_type *) pfd->client_data;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe event_conn_state_t *cs = (event_conn_state_t *) pt->baton;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* trash the connection; we couldn't queue the connected
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * socket to a worker
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_server_conf, APLOGNO(00471) "push2worker: ap_queue_push failed");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/* get_worker:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * If *have_idle_worker_p == 0, reserve a worker thread, and set
f4c310fd2555c6faca1f980f00b161eadb089023gstein * *have_idle_worker_p = 1.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * If *have_idle_worker_p is already 1, will do nothing.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If blocking == 1, block if all workers are currently busy.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If no worker was available immediately, will set *all_busy to 1.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: If there are no workers, we should not block immediately but
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: close all keep-alive connections first.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void get_worker(int *have_idle_worker_p, int blocking, int *all_busy)
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* already reserved a worker thread - must have hit a
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * transient error on a previous pass
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = ap_queue_info_wait_for_idler(worker_queue_info, all_busy);
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf, APLOGNO(00472)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "ap_queue_info_wait_for_idler failed. "
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein "Attempting to shutdown process gracefully");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/* Structures to reuse */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic APR_RING_HEAD(timer_free_ring_t, timer_event_t) timer_free_ring;
f94aab38f6ee899f463f0118ea395291f7c5b4cegsteinstatic int indexing_comp(void *a, void *b)
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_t t1 = (apr_time_t) (((timer_event_t *) a)->when);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t event_register_timed_callback(apr_time_t t,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* oh yeah, and make locking smarter/fine grained. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!APR_RING_EMPTY(&timer_free_ring, timer_event_t, link)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein te = apr_skiplist_alloc(timer_skiplist, sizeof(timer_event_t));
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* XXXXX: optimize */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* Okay, insert sorted by when.. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Close socket and clean up if remote closed its end while we were in
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * lingering close.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Only to be called in the listener thread;
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Pre-condition: cs is in one of the linger queues and in the pollset
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void process_lingering_close(event_conn_state_t *cs, const apr_pollfd_t *pfd)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe q = (cs->pub.state == CONN_STATE_LINGER_SHORT) ? &short_linger_q : &linger_q;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* socket is already in non-blocking state */
b6126f9c87296cf2cd10b0a39f7330a9d50e68d7gstein/* call 'func' for all elements of 'q' with timeout less than 'timeout_time'.
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * Pre-condition: timeout_mutex must already be locked
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Post-condition: timeout_mutex will be locked again
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void process_timeout_queue(struct timeout_queue *q,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe AP_DEBUG_ASSERT(!APR_RING_EMPTY(&q->head, event_conn_state_t, timeout_list));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (cs != APR_RING_SENTINEL(&q->head, event_conn_state_t, timeout_list)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rv != APR_SUCCESS && !APR_STATUS_IS_NOTFOUND(rv)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, cs->c, APLOGNO(00473)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "apr_pollset_remove failed");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_t *ptrans; /* Pool for per-transaction stuff */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* the following times out events that are really close in the future
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * to prevent extra poll calls
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * current value is .1 second
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "failed to initialize pollset, "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "attempting to shutdown process gracefully");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Unblock the signal used to wake this thread up, and set a handler for
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* trace log status every second */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein "connections: %u (clogged: %u write-completion: %d "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "keep-alive: %d lingering: %d suspended: %u)",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* TOOD: what should do here? ugh. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = apr_pollset_poll(event_pollset, timeout_interval, &num, &out_pfd);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_CRIT, rc, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "apr_pollset_poll failed. Attempting to "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "shutdown process gracefully");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* one of the sockets is readable */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe struct timeout_queue *remove_from_q = &write_completion_q;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* don't wait for a worker for a keepalive request */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* FALL THROUGH */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Some of the pollset backends, like KQueue or Epoll
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * automagically remove the FD if the socket is closed,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * therefore, we can accept _SUCCESS or _NOTFOUND,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * and we still want to keep going
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rc != APR_SUCCESS && !APR_STATUS_IS_NOTFOUND(rc)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "pollset remove failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If we didn't get a worker immediately for a keep-alive
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * request, we close the connection, so that the client can
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * re-connect to a different process.
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein "event_loop: unexpected state %d",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* A Listener Socket is ready for an accept() */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein "All workers busy, not accepting new conns "
00f73f5096966f34c7db15562e5d2e1233eb4571gstein "in this process");
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Too many open connections (%u), "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "not accepting new conns in this process",
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
707ecf9559338ec06b24334bc9abcca670325cc4gstein "Idle workers: %u",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* create a new transaction pool for each accepted socket */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Failed to create transaction pool");
f4c310fd2555c6faca1f980f00b161eadb089023gstein get_worker(&have_idle_worker, 1, &workers_were_busy);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* later we trash rv and rely on csd to indicate
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* E[NM]FILE, ENOMEM, etc */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* trash the connection; we couldn't queue the connected
707ecf9559338ec06b24334bc9abcca670325cc4gstein * socket to a worker
707ecf9559338ec06b24334bc9abcca670325cc4gstein "ap_queue_push failed");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe } /* if:else on pt->type */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* send socket to serf. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* XXXX: this doesn't require get_worker() */
f4c310fd2555c6faca1f980f00b161eadb089023gstein } /* while for processing poll */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* TODO: break out to separate function */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX possible optimization: stash the current time for use as
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * r->request_time for new requests
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we only do this once per 0.1s (TIMEOUT_FUDGE_FACTOR) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* handle timed out sockets */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Step 1: keepalive timeouts */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If all workers are busy, we kill older keep-alive connections so that they
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * may connect to another process.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "All workers are busy, will close %d keep-alive "
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm "connections",
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* add in an extra 2sec fudge factor */
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein /* Step 2: write completion timeouts */
f4c310fd2555c6faca1f980f00b161eadb089023gstein process_timeout_queue(&write_completion_q, timeout_time,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Step 3: (normal) lingering close completion timeouts */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe process_timeout_queue(&linger_q, timeout_time, stop_lingering_close);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Step 4: (short) lingering close completion timeouts */
f4c310fd2555c6faca1f980f00b161eadb089023gstein process_timeout_queue(&short_linger_q, timeout_time, stop_lingering_close);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ps->connections = apr_atomic_read32(&connection_count);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein ps->lingering_close = apr_atomic_read32(&lingering_count);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ((int)ap_queue_info_get_idlers(worker_queue_info) - 1) *
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein worker_factor / WORKER_FACTOR_SCALE + threads_per_child)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * XXX: do we need to set some timeout that re-enables the listensocks
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * XXX: in case no other event occurs?
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein } /* listener main loop */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/* XXX For ungraceful termination/restart, we definitely don't want to
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * wait for active connections to finish but we may want to wait
f4c310fd2555c6faca1f980f00b161eadb089023gstein * for idle workers to get out of the queue code and release mutexes,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * since those mutexes are cleaned up pretty soon and some systems
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * may not react favorably (i.e., segfault) if operations are attempted
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * on cleaned-up mutexes.
f54da7877f9e092465df38bfda142f3e71dbb7aawrowestatic void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_t *ptrans; /* Pool for per-transaction stuff */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current();
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein ap_update_child_status_from_indexes(process_slot, thread_slot,
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_queue_info_set_idle(worker_queue_info, NULL);
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "ap_queue_info_set_idle failed. Attempting to "
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein "shutdown process gracefully.");
bbba27074551817d7c6a606c4362965c26a0777egstein ap_update_child_status_from_indexes(process_slot, thread_slot,
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein rv = ap_queue_pop_something(worker_queue, &csd, &cs, &ptrans, &te);
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein /* We get APR_EOF during a graceful shutdown once all the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * connections accepted by this server process have been handled.
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* We get APR_EINTR whenever ap_queue_pop() has been interrupted
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * from an explicit call to ap_queue_interrupt_all(). This allows
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * us to unblock threads stuck in ap_queue_pop() when a shutdown
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * is pending.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * If workers_may_exit is set and this is ungraceful termination/
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * restart, we are bound to get an error on some systems (e.g.,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * AIX, which sanity-checks mutex operations) since the queue
f4c310fd2555c6faca1f980f00b161eadb089023gstein * may have already been cleaned up. Don't log the "error" if
f4c310fd2555c6faca1f980f00b161eadb089023gstein * workers_may_exit is set.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We got some other error. */
dd56b1dd453bd9032d97028bc3987f999c31280cwrowe ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_pop failed");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe APR_RING_INSERT_TAIL(&timer_free_ring, te, timer_event_t, link);
5646ba89a25a695006edae46de226fb57a2e6270gstein process_socket(thd, ptrans, csd, cs, eq, process_slot, thread_slot);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(process_slot, thread_slot,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void create_listener_thread(thread_starter * ts)
f4c310fd2555c6faca1f980f00b161eadb089023gstein my_info = (proc_info *) ap_malloc(sizeof(proc_info));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe my_info->tid = -1; /* listener thread doesn't have a thread slot */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(00474)
bbba27074551817d7c6a606c4362965c26a0777egstein "apr_thread_create: unable to create listener thread");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* let the parent decide how bad this really is */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/* XXX under some circumstances not understood, children can get stuck
1448efd1befdbe16fe42532edbc379204279aadfasteinmetz * in start_threads forever trying to take over slots which will
f4c310fd2555c6faca1f980f00b161eadb089023gstein * never be cleaned up; for now there is an APLOG_DEBUG message issued
f4c310fd2555c6faca1f980f00b161eadb089023gstein * every so often when this condition occurs
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy)
f4c310fd2555c6faca1f980f00b161eadb089023gstein int good_methods[] = {APR_POLLSET_KQUEUE, APR_POLLSET_PORT, APR_POLLSET_EPOLL};
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein /* We must create the fd queues before we start up the listener
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and worker threads. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_queue_init(worker_queue, threads_per_child, pchild);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
bbba27074551817d7c6a606c4362965c26a0777egstein "ap_queue_init() failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ap_max_mem_free != APR_ALLOCATOR_MAX_FREE_UNLIMITED) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If we want to conserve memory, let's not keep an unlimited number of
f4c310fd2555c6faca1f980f00b161eadb089023gstein * pools & allocators.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * XXX: This should probably be a separate config directive
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_info_create() failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Create the main pollset */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (i = 0; i < sizeof(good_methods) / sizeof(void*); i++) {
066877f1a045103acfdd376d48cdd473c33f409bdougm threads_per_child*2, /* XXX don't we need more, to handle
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * connections in K-A or lingering
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pchild, APR_POLLSET_WAKEABLE|APR_POLLSET_NOCOPY|APR_POLLSET_NODEFAULT,
f4c310fd2555c6faca1f980f00b161eadb089023gstein threads_per_child*2, /* XXX don't we need more, to handle
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * connections in K-A or lingering
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_pollset_create failed; check system or user limits");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02472)
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein "start_threads: Using %s", apr_pollset_method_name(event_pollset));
709df1e1c2e1710570f8cb4209497e88662829c3gstein worker_sockets = apr_pcalloc(pchild, threads_per_child
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein * sizeof(apr_socket_t *));
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein worker_equeues = apr_palloc(pchild, threads_per_child * sizeof(ap_equeue_t*));
67ec15681c83d4f5e119f0742618569017beb3fbstriker for (i = 0; i < threads_per_child; i++) {
bf8de10e1e04cd6019ba4e23ebebcc1eaee5d4bagstein /* TODO: research/test optimal size of queue here */
bf8de10e1e04cd6019ba4e23ebebcc1eaee5d4bagstein ap_equeue_create(pchild, 16, sizeof(pollset_op_t), &eq);
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein /* same as thread ID */
066877f1a045103acfdd376d48cdd473c33f409bdougm while (1) {
6b745319b1099edacf401e8911efa480440f999agstein /* threads_per_child does not include the listener thread */
e2308c8c7aadbaa73ea513863b49848e34b99353wrowe for (i = 0; i < threads_per_child; i++) {
6b745319b1099edacf401e8911efa480440f999agstein ap_scoreboard_image->servers[child_num_arg][i].status;
acdb373d92c698a2ac260e03da95816c8a091eb6gstein if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
acdb373d92c698a2ac260e03da95816c8a091eb6gstein my_info = (proc_info *) ap_malloc(sizeof(proc_info));
6b745319b1099edacf401e8911efa480440f999agstein /* We are creating threads right now */
acdb373d92c698a2ac260e03da95816c8a091eb6gstein /* We let each thread update its own scoreboard entry. This is
acdb373d92c698a2ac260e03da95816c8a091eb6gstein * done because it lets us deal with tid better.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "apr_thread_create: unable to create worker thread");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* let the parent decide how bad this really is */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* Start the listener only when there are workers available */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (start_thread_may_exit || threads_created == threads_per_child) {
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* wait for previous generation to clean up an entry */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
6b745319b1099edacf401e8911efa480440f999agstein "slots very quickly (%d of %d)",
75ba48124689705b1eee2b4fe10fe24a2d2467cdgstein /* What state should this child_main process be listed as in the
return NULL;
if (listener) {
int iter;
iter = 0;
++iter;
for (i = 0; i < threads_per_child; i++) {
for (i = 0; i < num_buckets; i++) {
while(lr) {
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
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
for (i = 0; i < num_buckets; i++) {
status) == 0) {
else if (remaining_children_to_start) {
for (i = 0; i < num_buckets; i++) {
return DONE;
set_signals();
ap_log_common(s);
for (i = 0; i < num_buckets; i++) {
if (!child_fatal) {
return DONE;
} else if (shutdown_pending) {
int active_children;
int index;
for (i = 0; i < num_buckets; i++) {
if (!child_fatal) {
if (ap_graceful_shutdown_timeout) {
shutdown_pending = 0;
active_children = 0;
for (i = 0; i < num_buckets; i++) {
return DONE;
if (one_process) {
return DONE;
/* wake up the children...time to die. But we'll have more soon */
for (i = 0; i < num_buckets; i++) {
for (i = 0; i < num_buckets; i++) {
return OK;
int startup = 0;
int level_flags = 0;
int num_of_cores = 0;
pconf = p;
return DONE;
if (have_so_reuseport) {
#ifdef _SC_NPROCESSORS_ONLN
if (!one_process) {
for (i = 0; i < num_buckets; i++) {
return DONE;
return OK;
if (debug) {
no_detach = 0;
if (!retained) {
return HTTP_INTERNAL_SERVER_ERROR;
for (i = 0; i< num_buckets; i++) {
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;
ap_force_set_tz(p);
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}