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
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * http://www.apache.org/licenses/LICENSE-2.0
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
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.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/**
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This MPM tries to fix the 'keep alive problem' in HTTP.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
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 *
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.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *
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.
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein *
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 *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * For NetBSD, use at least 2.0.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * For Linux, you should use a 2.6 kernel, and make sure your glibc has epoll
f4c310fd2555c6faca1f980f00b161eadb089023gstein * support compiled in.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr.h"
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm#include "apr_portable.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_strings.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_file_io.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_thread_proc.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_signal.h"
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein#include "apr_thread_mutex.h"
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein#include "apr_poll.h"
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein#include "apr_ring.h"
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein#include "apr_queue.h"
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein#include "apr_atomic.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define APR_WANT_STRFUNC
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_want.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if APR_HAVE_UNISTD_H
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include <unistd.h>
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
707ecf9559338ec06b24334bc9abcca670325cc4gstein#if APR_HAVE_SYS_SOCKET_H
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include <sys/socket.h>
707ecf9559338ec06b24334bc9abcca670325cc4gstein#endif
707ecf9559338ec06b24334bc9abcca670325cc4gstein#if APR_HAVE_SYS_WAIT_H
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein#include <sys/wait.h>
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef HAVE_SYS_PROCESSOR_H
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include <sys/processor.h> /* for bindprocessor() */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein#if !APR_HAS_THREADS
707ecf9559338ec06b24334bc9abcca670325cc4gstein#error The EventOpt MPM requires APR threads, but they are unavailable.
707ecf9559338ec06b24334bc9abcca670325cc4gstein#endif
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "ap_config.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "httpd.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "http_main.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "http_log.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "http_config.h" /* for read_config */
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "http_core.h" /* for get_remote_host */
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "http_connection.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "ap_mpm.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "mpm_common.h"
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#include "ap_listen.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "scoreboard.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "fdqueue.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "mpm_default.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "http_vhost.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "unixd.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein#include "util_time.h"
707ecf9559338ec06b24334bc9abcca670325cc4gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include <signal.h>
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include <limits.h> /* for INT_MAX */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "equeue.h"
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#include "apr_skiplist.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if HAVE_SERF
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "mod_serf.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "serf.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#ifndef DEFAULT_SERVER_LIMIT
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#define DEFAULT_SERVER_LIMIT 16
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#endif
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * some sort of compile-time limit to help catch typos.
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein */
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#ifndef MAX_SERVER_LIMIT
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#define MAX_SERVER_LIMIT 20000
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Limit on the threads per process. Clients will be locked out if more than
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * this are needed.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
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 */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#ifndef DEFAULT_THREAD_LIMIT
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define DEFAULT_THREAD_LIMIT 64
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#endif
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * some sort of compile-time limit to help catch typos.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#ifndef MAX_THREAD_LIMIT
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define MAX_THREAD_LIMIT 100000
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#endif
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#ifndef MAX_SECS_TO_LINGER
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define MAX_SECS_TO_LINGER 30
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#endif
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define SECONDS_TO_LINGER 2
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/*
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * Actual definitions of config globals
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#ifndef DEFAULT_WORKER_FACTOR
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#define DEFAULT_WORKER_FACTOR 2
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein#endif
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein#define WORKER_FACTOR_SCALE 16 /* scale factor to allow fractional values */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic unsigned int worker_factor = DEFAULT_WORKER_FACTOR * WORKER_FACTOR_SCALE;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic int threads_per_child = 0; /* Worker threads per child */
956f4b1551215610a57f3b52822dbac6f41a8aa9gsteinstatic int ap_daemons_to_start = 0;
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 start_thread_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;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic fd_queue_t *worker_queue;
e8f95a682820a599fe41b22977010636be5c2717jimstatic fd_queue_info_t *worker_queue_info;
9ec6440fdeb81f04905959293b381ebbfa3114c2jortonstatic int mpm_state = AP_MPMQ_STARTING;
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton
9ec6440fdeb81f04905959293b381ebbfa3114c2jortontypedef enum {
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton TIMEOUT_WRITE_COMPLETION,
f4c310fd2555c6faca1f980f00b161eadb089023gstein TIMEOUT_KEEPALIVE,
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein TIMEOUT_LINGER,
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein TIMEOUT_SHORT_LINGER
707ecf9559338ec06b24334bc9abcca670325cc4gstein} timeout_type_e;
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gsteinstruct event_conn_state_t {
707ecf9559338ec06b24334bc9abcca670325cc4gstein /** APR_RING of expiration timeouts */
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_RING_ENTRY(event_conn_state_t) timeout_list;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** the expiration time of the next keepalive timeout */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_t expiration_time;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** connection record this struct refers to */
f4c310fd2555c6faca1f980f00b161eadb089023gstein conn_rec *c;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /** memory pool to allocate from */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *p;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** bucket allocator */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_bucket_alloc_t *bucket_alloc;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** poll file descriptor information */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pollfd_t pfd;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /** public parts of the connection state */
f4c310fd2555c6faca1f980f00b161eadb089023gstein conn_state_t pub;
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
cc8241a7ee9815575a267e13eff62b6fddf1fe58gsteintypedef struct pollset_op_t {
f4c310fd2555c6faca1f980f00b161eadb089023gstein timeout_type_e timeout_type;
f4c310fd2555c6faca1f980f00b161eadb089023gstein event_conn_state_t *cs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *tag;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} pollset_op_t;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinAPR_RING_HEAD(timeout_head_t, event_conn_state_t);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstruct timeout_queue {
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct timeout_head_t head;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int count;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *tag;
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe/*
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
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe */
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowestatic struct timeout_queue write_completion_q, keepalive_q, linger_q,
e8f95a682820a599fe41b22977010636be5c2717jim short_linger_q;
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowestatic apr_pollfd_t *listener_pollfd;
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe/*
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * Macros for accessing struct timeout_queue.
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * For TO_QUEUE_APPEND and TO_QUEUE_REMOVE, timeout_mutex must be held.
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe */
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe#define TO_QUEUE_APPEND(q, el) \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe do { \
e8f95a682820a599fe41b22977010636be5c2717jim APR_RING_INSERT_TAIL(&(q).head, el, event_conn_state_t, timeout_list); \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe (q).count++; \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe } while (0)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe#define TO_QUEUE_REMOVE(q, el) \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe do { \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe APR_RING_REMOVE(el, timeout_list); \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe (q).count--; \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe } while (0)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe#define TO_QUEUE_INIT(q) \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe do { \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe APR_RING_INIT(&(q).head, event_conn_state_t, timeout_list); \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe (q).tag = #q; \
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe } while (0)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe#define TO_QUEUE_ELEM_INIT(el) APR_RING_ELEM_INIT(el, timeout_list)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein/*
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_pollset_t *event_pollset;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if HAVE_SERF
01e8aca9299a0b872414c24c8b7724d6f88ae665ianhtypedef struct {
e8f95a682820a599fe41b22977010636be5c2717jim apr_pollset_t *pollset;
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein apr_pool_t *pool;
93ef028b3ac7dc86ec72204233b9d99c69587c54striker} s_baton_t;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic serf_context_t *g_serf;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/* The structure used to pass unique initialization info to each thread */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowetypedef struct
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein{
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein int pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int tid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int sd;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} proc_info;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Structure used to pass information to the thread responsible for
f4c310fd2555c6faca1f980f00b161eadb089023gstein * creating the rest of the threads.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowetypedef struct
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe{
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe apr_thread_t **threads;
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein apr_thread_t *listener;
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein int child_num_arg;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_threadattr_t *threadattr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} thread_starter;
7f69a90d847f08a86f9909c2c5129408697a9600jorton
7f69a90d847f08a86f9909c2c5129408697a9600jortontypedef enum
7f69a90d847f08a86f9909c2c5129408697a9600jorton{
f4c310fd2555c6faca1f980f00b161eadb089023gstein PT_CSD,
f4c310fd2555c6faca1f980f00b161eadb089023gstein PT_ACCEPT
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm#if HAVE_SERF
f4c310fd2555c6faca1f980f00b161eadb089023gstein , PT_SERF
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
7f69a90d847f08a86f9909c2c5129408697a9600jorton} poll_type_e;
7f69a90d847f08a86f9909c2c5129408697a9600jorton
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein poll_type_e type;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm void *baton;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm} listener_poll_type;
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton
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
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct event_retained_data {
7f69a90d847f08a86f9909c2c5129408697a9600jorton int first_server_limit;
7f69a90d847f08a86f9909c2c5129408697a9600jorton int first_thread_limit;
7f69a90d847f08a86f9909c2c5129408697a9600jorton int module_loads;
ebf7895684796436b808025426cbfab96d57910dnd int sick_child_detected;
ebf7895684796436b808025426cbfab96d57910dnd ap_generation_t my_generation;
7f69a90d847f08a86f9909c2c5129408697a9600jorton int volatile is_graceful; /* set from signal handler */
7f69a90d847f08a86f9909c2c5129408697a9600jorton int maxclients_reported;
ebf7895684796436b808025426cbfab96d57910dnd /*
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.
e8f95a682820a599fe41b22977010636be5c2717jim */
7f69a90d847f08a86f9909c2c5129408697a9600jorton int max_daemons_limit;
7f69a90d847f08a86f9909c2c5129408697a9600jorton /*
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.
e8f95a682820a599fe41b22977010636be5c2717jim */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int *idle_spawn_rate;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#ifndef MAX_SPAWN_RATE
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define MAX_SPAWN_RATE (32)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein int hold_off_on_exponential_spawning;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} event_retained_data;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic event_retained_data *retained;
e8f95a682820a599fe41b22977010636be5c2717jim
7f69a90d847f08a86f9909c2c5129408697a9600jorton#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic ap_pod_t **pod;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic ap_pod_t *child_pod;
9ec6440fdeb81f04905959293b381ebbfa3114c2jortonstatic ap_listen_rec *child_listen;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int *bucket; /* bucket array for the httpd child processes */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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.).
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int one_process = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#ifdef DEBUG_SIGSTOP
6f15570e3adc0faf87bf55f70857028276fc9e32wroweint raise_sigstop_flags;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_pool_t *pconf; /* Pool for config stuff */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_pool_t *pchild; /* Pool for httpd child stuff */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
f4c310fd2555c6faca1f980f00b161eadb089023gstein thread. Use this instead */
7ac747af0cf476c2276aaf9999425e1b52bf5f64jortonstatic pid_t parent_pid;
7ac747af0cf476c2276aaf9999425e1b52bf5f64jortonstatic apr_os_thread_t *listener_os_thread;
7ac747af0cf476c2276aaf9999425e1b52bf5f64jorton
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 */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define LISTENER_SIGNAL SIGHUP
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* An array of socket descriptors in use by each thread used to
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * perform a non-graceful (forced) shutdown of the server.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_socket_t **worker_sockets;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic ap_equeue_t **worker_equeues;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void disable_listensocks(int process_slot)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton int i;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (i = 0; i < num_listensocks; i++) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pollset_remove(event_pollset, &listener_pollfd[i]);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[process_slot].not_accepting = 1;
066877f1a045103acfdd376d48cdd473c33f409bdougm}
066877f1a045103acfdd376d48cdd473c33f409bdougm
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void enable_listensocks(int process_slot)
da9adab0554faf94f8cc2705c2363aceacf75c46gstein{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int i;
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 apr_atomic_read32(&connection_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_read32(&lingering_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_read32(&clogged_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_read32(&suspended_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_queue_info_get_idlers(worker_queue_info));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (i = 0; i < num_listensocks; i++)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pollset_add(event_pollset, &listener_pollfd[i]);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
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 */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_scoreboard_image->parent[process_slot].not_accepting = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void close_worker_sockets(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i;
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (worker_sockets[i]) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_close(worker_sockets[i]);
f4c310fd2555c6faca1f980f00b161eadb089023gstein worker_sockets[i] = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void wakeup_listener(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein listener_may_exit = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!listener_os_thread) {
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* unblock the listener if it's waiting for a worker */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_queue_info_term(worker_queue_info);
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe /*
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 */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm#ifdef HAVE_PTHREAD_KILL
f4c310fd2555c6faca1f980f00b161eadb089023gstein pthread_kill(*listener_os_thread, LISTENER_SIGNAL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#else
f4c310fd2555c6faca1f980f00b161eadb089023gstein kill(ap_my_pid, LISTENER_SIGNAL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
066877f1a045103acfdd376d48cdd473c33f409bdougm}
4c449c30215bd5e8bad122a4118f5a7b0e995472wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define ST_INIT 0
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define ST_GRACEFUL 1
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define ST_UNGRACEFUL 2
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int terminate_mode = ST_INIT;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void signal_threads(int mode)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe if (terminate_mode == mode) {
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe return;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe terminate_mode = mode;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe mpm_state = AP_MPMQ_STOPPING;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* in case we weren't called from the listener thread, wake up the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener thread
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein wakeup_listener();
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (mode == ST_UNGRACEFUL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein workers_may_exit = 1;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ap_queue_interrupt_all(worker_queue);
f4c310fd2555c6faca1f980f00b161eadb089023gstein close_worker_sockets(); /* forcefully kill all current connections */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
5646ba89a25a695006edae46de226fb57a2e6270gstein}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int event_query(int query_code, int *result, apr_status_t *rv)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *rv = APR_SUCCESS;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe switch (query_code) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case AP_MPMQ_MAX_DAEMON_USED:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = retained->max_daemons_limit;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein break;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein case AP_MPMQ_IS_THREADED:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *result = AP_MPMQ_STATIC;
7f69a90d847f08a86f9909c2c5129408697a9600jorton break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_IS_FORKED:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = AP_MPMQ_DYNAMIC;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_IS_ASYNC:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = 1;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case AP_MPMQ_HAS_SERF:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *result = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_HARD_LIMIT_DAEMONS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = server_limit;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_HARD_LIMIT_THREADS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = thread_limit;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_MAX_THREADS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = threads_per_child;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_MIN_SPARE_DAEMONS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein case AP_MPMQ_MIN_SPARE_THREADS:
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein *result = min_spare_threads;
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_MAX_SPARE_DAEMONS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_MAX_SPARE_THREADS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = max_spare_threads;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case AP_MPMQ_MAX_REQUESTS_DAEMON:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *result = ap_max_requests_per_child;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case AP_MPMQ_MAX_DAEMONS:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = ap_daemons_limit;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_MPM_STATE:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *result = mpm_state;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case AP_MPMQ_GENERATION:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *result = retained->my_generation;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case AP_MPMQ_CAN_SUSPEND:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *result = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe default:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *rv = APR_ENOTIMPL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return OK;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void event_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (childnum != -1) { /* child had a scoreboard slot? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_run_child_status(ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_scoreboard_image->parent[childnum].pid,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_scoreboard_image->parent[childnum].generation,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe childnum, MPM_CHILD_EXITED);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[childnum].pid = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void event_note_child_started(int slot, pid_t pid)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[slot].pid = pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_run_child_status(ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[slot].pid,
da9adab0554faf94f8cc2705c2363aceacf75c46gstein retained->my_generation, slot, MPM_CHILD_STARTED);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
cc8241a7ee9815575a267e13eff62b6fddf1fe58gsteinstatic void event_note_child_lost_slot(int slot, pid_t newpid)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein{
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 "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "%" APR_PID_T_FMT "%s",
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm newpid,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_scoreboard_image->parent[slot].pid,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_scoreboard_image->parent[slot].quiescing ?
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe " (quiescing)" : "");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_run_child_status(ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[slot].pid,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[slot].generation,
da9adab0554faf94f8cc2705c2363aceacf75c46gstein slot, MPM_CHILD_LOST_SLOT);
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[slot].generation);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic const char *event_get_name(void)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return "eventopt";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
da9adab0554faf94f8cc2705c2363aceacf75c46gstein/* a clean exit from a child with proper cleanup */
da9adab0554faf94f8cc2705c2363aceacf75c46gsteinstatic void clean_child_exit(int code) __attribute__ ((noreturn));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void clean_child_exit(int code)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe mpm_state = AP_MPMQ_STOPPING;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (pchild) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_destroy(pchild);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (one_process) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein event_note_child_killed(/* slot */ 0, 0, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein exit(code);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void just_die(int sig)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein clean_child_exit(0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f39230a531b23d94f86a087963299bbe2e431a4agstein/*****************************************************************
f39230a531b23d94f86a087963299bbe2e431a4agstein * Connection structures and accounting...
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int child_fatal;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* volatile because they're updated from a signal handler */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int volatile shutdown_pending;
49bf4df23d9e5281abcd83005550bda818b17b08wrowestatic int volatile restart_pending;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t decrement_connection_count(void *cs_)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein event_conn_state_t *cs = cs_;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm switch (cs->pub.state) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case CONN_STATE_LINGER_NORMAL:
f4c310fd2555c6faca1f980f00b161eadb089023gstein case CONN_STATE_LINGER_SHORT:
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein apr_atomic_dec32(&lingering_count);
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein break;
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein case CONN_STATE_SUSPENDED:
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_atomic_dec32(&suspended_count);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein break;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein default:
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_atomic_dec32(&connection_count);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return APR_SUCCESS;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgsteinstatic void ap_start_shutdown(int graceful)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein mpm_state = AP_MPMQ_STOPPING;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (shutdown_pending == 1) {
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.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
f4c310fd2555c6faca1f980f00b161eadb089023gstein return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe shutdown_pending = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein retained->is_graceful = graceful;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* do a graceful restart if graceful == 1 */
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagsteinstatic void ap_start_restart(int graceful)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe mpm_state = AP_MPMQ_STOPPING;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (restart_pending == 1) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Probably not an error - don't bother reporting it */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe restart_pending = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe retained->is_graceful = graceful;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void sig_term(int sig)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void restart(int sig)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_start_restart(sig == AP_SIG_GRACEFUL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void set_signals(void)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#ifndef NO_USE_SIGACTION
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein struct sigaction sa;
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein#endif
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein if (!one_process) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_fatal_signal_setup(ap_server_conf, pconf);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#ifndef NO_USE_SIGACTION
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe sigemptyset(&sa.sa_mask);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe sa.sa_flags = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein sa.sa_handler = sig_term;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (sigaction(SIGTERM, &sa, NULL) < 0)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00459)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein "sigaction(SIGTERM)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef AP_SIG_GRACEFUL_STOP
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00460)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef SIGINT
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (sigaction(SIGINT, &sa, NULL) < 0)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00461)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe "sigaction(SIGINT)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
e2c92fb4350c626885aff64d3f92690a1892ca50wrowe#ifdef SIGXCPU
e2c92fb4350c626885aff64d3f92690a1892ca50wrowe sa.sa_handler = SIG_DFL;
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe if (sigaction(SIGXCPU, &sa, NULL) < 0)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00462)
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein "sigaction(SIGXCPU)");
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein#endif
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein#ifdef SIGXFSZ
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 sa.sa_handler = SIG_IGN;
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe if (sigaction(SIGXFSZ, &sa, NULL) < 0)
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00463)
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe "sigaction(SIGXFSZ)");
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe#endif
e2c92fb4350c626885aff64d3f92690a1892ca50wrowe#ifdef SIGPIPE
e8f95a682820a599fe41b22977010636be5c2717jim sa.sa_handler = SIG_IGN;
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe if (sigaction(SIGPIPE, &sa, NULL) < 0)
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00464)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGPIPE)");
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
f4c310fd2555c6faca1f980f00b161eadb089023gstein * processing one */
f4c310fd2555c6faca1f980f00b161eadb089023gstein sigaddset(&sa.sa_mask, SIGHUP);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein sa.sa_handler = restart;
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein if (sigaction(SIGHUP, &sa, NULL) < 0)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00465)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGHUP)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
e8f95a682820a599fe41b22977010636be5c2717jim ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00466)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(" AP_SIG_GRACEFUL_STRING ")");
f4c310fd2555c6faca1f980f00b161eadb089023gstein#else
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!one_process) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm#ifdef SIGXCPU
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_signal(SIGXCPU, SIG_DFL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGXCPU */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef SIGXFSZ
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein apr_signal(SIGXFSZ, SIG_IGN);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGXFSZ */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_signal(SIGTERM, sig_term);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef SIGHUP
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_signal(SIGHUP, restart);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGHUP */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef AP_SIG_GRACEFUL
e8f95a682820a599fe41b22977010636be5c2717jim apr_signal(AP_SIG_GRACEFUL, restart);
2dc8d653749bc319011afe9b02434c80a815d175trawick#endif /* AP_SIG_GRACEFUL */
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe#ifdef AP_SIG_GRACEFUL_STOP
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* AP_SIG_GRACEFUL_STOP */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef SIGPIPE
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein apr_signal(SIGPIPE, SIG_IGN);
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein#endif /* SIGPIPE */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int process_pollop(pollset_op_t *op)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein event_conn_state_t *cs = op->cs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (op->timeout_type) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case TIMEOUT_WRITE_COMPLETION:
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_APPEND(write_completion_q, cs);
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe break;
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe case TIMEOUT_KEEPALIVE:
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein TO_QUEUE_APPEND(keepalive_q, cs);
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe break;
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe case TIMEOUT_LINGER:
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_APPEND(linger_q, cs);
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case TIMEOUT_SHORT_LINGER:
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_APPEND(short_linger_q, cs);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_pollset_add(event_pollset, &op->cs->pfd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) {
49bf4df23d9e5281abcd83005550bda818b17b08wrowe ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(00467)
49bf4df23d9e5281abcd83005550bda818b17b08wrowe "%s: apr_pollset_add failure", op->tag);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_close(cs->pfd.desc.s);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_clear(cs->p);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_push_pool(worker_queue_info, cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
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.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic int start_lingering_close(event_conn_state_t *cs, ap_equeue_t *eq)
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton{
f4c310fd2555c6faca1f980f00b161eadb089023gstein int ret = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *csd = ap_get_conn_socket(cs->c);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pollset_op_t localv;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pollset_op_t *v;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (eq) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe v = ap_equeue_writer_value(eq);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe v = &localv;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#ifdef AP_DEBUG
f4c310fd2555c6faca1f980f00b161eadb089023gstein {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv = apr_socket_timeout_set(csd, 0);
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton AP_DEBUG_ASSERT(rv == APR_SUCCESS);
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton }
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton#else
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_socket_timeout_set(csd, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein /*
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (apr_table_get(cs->c->notes, "short-lingering-close")) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->expiration_time =
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_now() + apr_time_from_sec(SECONDS_TO_LINGER);
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->timeout_type = TIMEOUT_SHORT_LINGER;
066877f1a045103acfdd376d48cdd473c33f409bdougm v->tag = "start_lingering_close(short)";
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.state = CONN_STATE_LINGER_SHORT;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs->expiration_time =
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_now() + apr_time_from_sec(MAX_SECS_TO_LINGER);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe v->timeout_type = TIMEOUT_LINGER;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe v->tag = "start_lingering_close(normal)";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs->pub.state = CONN_STATE_LINGER_NORMAL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_atomic_inc32(&lingering_count);
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pfd.reqevents = (
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT :
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_POLLIN) | APR_POLLHUP | APR_POLLERR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.sense = CONN_SENSE_DEFAULT;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->cs = cs;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (eq != NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_equeue_writer_onward(eq);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_pollset_wakeup(event_pollset);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
066877f1a045103acfdd376d48cdd473c33f409bdougm else {
07648ef03a5547fc4ed4410054d4161c142add50wrowe ret = process_pollop(v);
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein }
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein return ret;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein}
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/*
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic int start_lingering_close_blocking(event_conn_state_t *cs, ap_equeue_t *eq)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
066877f1a045103acfdd376d48cdd473c33f409bdougm if (ap_start_lingering_close(cs->c)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_clear(cs->p);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_push_pool(worker_queue_info, cs->p);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return start_lingering_close(cs, eq);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
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
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic int start_lingering_close_nonblocking(event_conn_state_t *cs, ap_equeue_t *eq)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein conn_rec *c = cs->c;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *csd = cs->pfd.desc.s;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (c->aborted
f4c310fd2555c6faca1f980f00b161eadb089023gstein || apr_socket_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS) {
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein apr_socket_close(csd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_clear(cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_push_pool(worker_queue_info, cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein return start_lingering_close(cs, eq);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * forcibly close a lingering connection after the lingering period has
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein * expired
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)
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int stop_lingering_close(event_conn_state_t *cs, ap_equeue_t *eq)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *csd = ap_get_conn_socket(cs->c);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "socket reached timeout in lingering-close state");
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_socket_close(csd);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein if (rv != APR_SUCCESS) {
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(00468) "error closing socket");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein AP_DEBUG_ASSERT(0);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein }
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_pool_clear(cs->p);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_push_pool(worker_queue_info, cs->p);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein return 0;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein}
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein/*
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * process one connection in the worker
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein */
b6c56e35c5ebdbe1da09806714fb579f3b8c648egsteinstatic void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * sock,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein event_conn_state_t * cs,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_equeue_t *eq,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein int my_child_num,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein int my_thread_num)
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein conn_rec *c;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein int rc;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_sb_handle_t *sbh;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein if (cs == NULL) { /* This is a new connection */
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley listener_poll_type *pt = apr_pcalloc(p, sizeof(*pt));
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein cs = apr_pcalloc(p, sizeof(event_conn_state_t));
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein cs->bucket_alloc = apr_bucket_alloc_create(p);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein c = ap_run_create_connection(p, ap_server_conf, sock,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein conn_id, sbh, cs->bucket_alloc);
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley if (!c) {
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_bucket_alloc_destroy(cs->bucket_alloc);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_pool_clear(p);
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley ap_push_pool(worker_queue_info, p);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein return;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein }
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_atomic_inc32(&connection_count);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_pool_cleanup_register(c->pool, cs, decrement_connection_count,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein apr_pool_cleanup_null);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein c->current_thread = thd;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein cs->c = c;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein c->cs = &(cs->pub);
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->p = p;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pfd.desc_type = APR_POLL_SOCKET;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein cs->pfd.reqevents = APR_POLLIN;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein cs->pfd.desc.s = sock;
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein pt->type = PT_CSD;
33397e35239f202a595837571561468f02b2e806gstein pt->baton = cs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pfd.client_data = pt;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ap_update_vhost_given_ip(c);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
066877f1a045103acfdd376d48cdd473c33f409bdougm rc = ap_run_pre_connection(c, sock);
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton if (rc != OK && rc != DONE) {
33397e35239f202a595837571561468f02b2e806gstein ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(00469)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "process_socket: connection aborted");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe c->aborted = 1;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein }
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton /**
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 *
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.sense = CONN_SENSE_DEFAULT;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein else {
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein c = cs->c;
f4c310fd2555c6faca1f980f00b161eadb089023gstein c->sbh = sbh;
707ecf9559338ec06b24334bc9abcca670325cc4gstein c->current_thread = thd;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein }
707ecf9559338ec06b24334bc9abcca670325cc4gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (c->clogging_input_filters && !c->aborted) {
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.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_inc32(&clogged_count);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_run_process_connection(c);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (cs->pub.state != CONN_STATE_SUSPENDED) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.state = CONN_STATE_LINGER;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
066877f1a045103acfdd376d48cdd473c33f409bdougm apr_atomic_dec32(&clogged_count);
707ecf9559338ec06b24334bc9abcca670325cc4gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wroweread_request:
707ecf9559338ec06b24334bc9abcca670325cc4gstein if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!c->aborted) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_run_process_connection(c);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* state will be updated upon return
e8f95a682820a599fe41b22977010636be5c2717jim * fall thru to either wait for readability/timeout or
e8f95a682820a599fe41b22977010636be5c2717jim * do lingering close
e8f95a682820a599fe41b22977010636be5c2717jim */
7f69a90d847f08a86f9909c2c5129408697a9600jorton }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs->pub.state = CONN_STATE_LINGER;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_filter_t *output_filter = c->output_filters;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (output_filter->next != NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein output_filter = output_filter->next;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = output_filter->frec->filter_func.out_func(output_filter, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "network write failure in core output filter");
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.state = CONN_STATE_LINGER;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else if (c->data_in_output_filters) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* Still in WRITE_COMPLETION_STATE:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Set a write timeout for this connection, and let the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * event thread poll for writeability.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein pollset_op_t *v = ap_equeue_writer_value(eq);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->expiration_time = ap_server_conf->timeout + apr_time_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein c->sbh = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pfd.reqevents = (
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN :
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_POLLOUT) | APR_POLLHUP | APR_POLLERR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.sense = CONN_SENSE_DEFAULT;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->cs = cs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->timeout_type = TIMEOUT_WRITE_COMPLETION;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->tag = "process_socket(write_completion)";
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_equeue_writer_onward(eq);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pollset_wakeup(event_pollset);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
f4c310fd2555c6faca1f980f00b161eadb089023gstein listener_may_exit) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.state = CONN_STATE_LINGER;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (c->data_in_input_filters) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
707ecf9559338ec06b24334bc9abcca670325cc4gstein goto read_request;
707ecf9559338ec06b24334bc9abcca670325cc4gstein }
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (cs->pub.state == CONN_STATE_LINGER) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein if (!start_lingering_close_blocking(cs, eq)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein c->sbh = NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein }
707ecf9559338ec06b24334bc9abcca670325cc4gstein }
707ecf9559338ec06b24334bc9abcca670325cc4gstein else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein pollset_op_t *v;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->expiration_time = ap_server_conf->keep_alive_timeout +
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein c->sbh = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Add work to pollset. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein v = ap_equeue_writer_value(eq);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe v->timeout_type = TIMEOUT_KEEPALIVE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->cs = cs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->pfd.reqevents = APR_POLLIN;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v->tag = "process_socket(keepalive)";
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_equeue_writer_onward(eq);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pollset_wakeup(event_pollset);
e8f95a682820a599fe41b22977010636be5c2717jim return;
7f69a90d847f08a86f9909c2c5129408697a9600jorton }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else if (cs->pub.state == CONN_STATE_SUSPENDED) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_inc32(&suspended_count);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
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 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein c->sbh = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ap_max_requests_per_child) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Stopping process due to MaxConnectionsPerChild");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe signal_threads(ST_GRACEFUL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* keep going */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe conns_this_child = APR_INT32_MAX;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void close_listeners(int process_slot, int *closed) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!*closed) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i;
f4c310fd2555c6faca1f980f00b161eadb089023gstein disable_listensocks(process_slot);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_close_listeners();
f4c310fd2555c6faca1f980f00b161eadb089023gstein *closed = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dying = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[process_slot].quiescing = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < threads_per_child; ++i) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(process_slot, i,
f4c310fd2555c6faca1f980f00b161eadb089023gstein SERVER_GRACEFUL, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* wake up the main thread */
f4c310fd2555c6faca1f980f00b161eadb089023gstein kill(ap_my_pid, SIGTERM);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void unblock_signal(int sig)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein sigset_t sig_mask;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein sigemptyset(&sig_mask);
f4c310fd2555c6faca1f980f00b161eadb089023gstein sigaddset(&sig_mask, sig);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#if defined(SIGPROCMASK_SETS_THREAD_MASK)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#else
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void dummy_signal_handler(int sig)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * then we don't need this goofy function.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#if HAVE_SERF
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_status_t s_socket_add(void *user_baton,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pollfd_t *pfd,
f4c310fd2555c6faca1f980f00b161eadb089023gstein void *serf_baton)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe s_baton_t *s = (s_baton_t*)user_baton;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* XXXXX: recycle listener_poll_types */
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe listener_poll_type *pt = ap_malloc(sizeof(*pt));
f4c310fd2555c6faca1f980f00b161eadb089023gstein pt->type = PT_SERF;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pt->baton = serf_baton;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pfd->client_data = pt;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return apr_pollset_add(s->pollset, pfd);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
e8f95a682820a599fe41b22977010636be5c2717jim
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowestatic apr_status_t s_socket_remove(void *user_baton,
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe apr_pollfd_t *pfd,
e8f95a682820a599fe41b22977010636be5c2717jim void *serf_baton)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe{
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe s_baton_t *s = (s_baton_t*)user_baton;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe listener_poll_type *pt = pfd->client_data;
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe free(pt);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return apr_pollset_remove(s->pollset, pfd);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t init_pollset(apr_pool_t *p)
5646ba89a25a695006edae46de226fb57a2e6270gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if HAVE_SERF
5646ba89a25a695006edae46de226fb57a2e6270gstein s_baton_t *baton = NULL;
5646ba89a25a695006edae46de226fb57a2e6270gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_listen_rec *lr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein listener_poll_type *pt;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_INIT(write_completion_q);
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_INIT(keepalive_q);
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_INIT(linger_q);
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_INIT(short_linger_q);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein listener_pollfd = apr_palloc(p, sizeof(apr_pollfd_t) * num_listensocks);
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (lr = child_listen; lr != NULL; lr = lr->next, i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pollfd_t *pfd;
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_DEBUG_ASSERT(i < num_listensocks);
f4c310fd2555c6faca1f980f00b161eadb089023gstein pfd = &listener_pollfd[i];
f4c310fd2555c6faca1f980f00b161eadb089023gstein pt = apr_pcalloc(p, sizeof(*pt));
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein pfd->desc_type = APR_POLL_SOCKET;
066877f1a045103acfdd376d48cdd473c33f409bdougm pfd->desc.s = lr->sd;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein pfd->reqevents = APR_POLLIN;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pt->type = PT_ACCEPT;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pt->baton = lr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein pfd->client_data = pt;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_opt_set(pfd->desc.s, APR_SO_NONBLOCK, 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pollset_add(event_pollset, pfd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein lr->accept_func = ap_unixd_accept;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#if HAVE_SERF
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe baton = apr_pcalloc(p, sizeof(*baton));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe baton->pollset = event_pollset;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* TODO: subpools, threads, reuse, etc. -- currently use malloc() inside :( */
f4c310fd2555c6faca1f980f00b161eadb089023gstein baton->pool = p;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
066877f1a045103acfdd376d48cdd473c33f409bdougm g_serf = serf_context_create_ex(baton,
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein s_socket_add,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe s_socket_remove, p);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_register_provider(p, "mpm_serf",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "instance", "0", g_serf);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return APR_SUCCESS;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t push_timer2worker(timer_event_t* te)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein return ap_queue_push_timer(worker_queue, te);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Pre-condition: pfd->cs is neither in pollset nor timeout queue
f4c310fd2555c6faca1f980f00b161eadb089023gstein * this function may only be called by the listener
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic apr_status_t push2worker(const apr_pollfd_t * pfd,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pollset_t * pollset)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe listener_poll_type *pt = (listener_poll_type *) pfd->client_data;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe event_conn_state_t *cs = (event_conn_state_t *) pt->baton;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_status_t rc;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rc != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* trash the connection; we couldn't queue the connected
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein * socket to a worker
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein apr_bucket_alloc_destroy(cs->bucket_alloc);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_close(cs->pfd.desc.s);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_server_conf, APLOGNO(00471) "push2worker: ap_queue_push failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_clear(cs->p);
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ap_push_pool(worker_queue_info, cs->p);
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return rc;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void get_worker(int *have_idle_worker_p, int blocking, int *all_busy)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rc;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*have_idle_worker_p) {
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* already reserved a worker thread - must have hit a
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * transient error on a previous pass
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (blocking)
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = ap_queue_info_wait_for_idler(worker_queue_info, all_busy);
f4c310fd2555c6faca1f980f00b161eadb089023gstein else
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = ap_queue_info_try_get_idler(worker_queue_info);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rc == APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein *have_idle_worker_p = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!blocking && rc == APR_EAGAIN) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein *all_busy = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!APR_STATUS_IS_EOF(rc)) {
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");
f4c310fd2555c6faca1f980f00b161eadb089023gstein signal_threads(ST_GRACEFUL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein}
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe/* Structures to reuse */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic APR_RING_HEAD(timer_free_ring_t, timer_event_t) timer_free_ring;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_skiplist *timer_skiplist;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f94aab38f6ee899f463f0118ea395291f7c5b4cegsteinstatic int indexing_comp(void *a, void *b)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
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 AP_DEBUG_ASSERT(t1);
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein AP_DEBUG_ASSERT(t2);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return ((t1 < t2) ? -1 : ((t1 > t2) ? 1 : 0));
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int indexing_compk(void *ac, void *b)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_t *t1 = (apr_time_t *) ac;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when);
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_DEBUG_ASSERT(t2);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return ((*t1 < t2) ? -1 : ((*t1 > t2) ? 1 : 0));
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_thread_mutex_t *g_timer_skiplist_mtx;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t event_register_timed_callback(apr_time_t t,
da9adab0554faf94f8cc2705c2363aceacf75c46gstein ap_mpm_callback_fn_t *cbfn,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe void *baton)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
f4c310fd2555c6faca1f980f00b161eadb089023gstein timer_event_t *te;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* oh yeah, and make locking smarter/fine grained. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_thread_mutex_lock(g_timer_skiplist_mtx);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!APR_RING_EMPTY(&timer_free_ring, timer_event_t, link)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein te = APR_RING_FIRST(&timer_free_ring);
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_RING_REMOVE(te, link);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein te = apr_skiplist_alloc(timer_skiplist, sizeof(timer_event_t));
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_RING_ELEM_INIT(te, link);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein te->cbfunc = cbfn;
f4c310fd2555c6faca1f980f00b161eadb089023gstein te->baton = baton;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* XXXXX: optimize */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein te->when = t + apr_time_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* Okay, insert sorted by when.. */
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe apr_skiplist_insert(timer_skiplist, (void *)te);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_thread_mutex_unlock(g_timer_skiplist_mtx);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein return APR_SUCCESS;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein}
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein/*
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
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void process_lingering_close(event_conn_state_t *cs, const apr_pollfd_t *pfd)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_socket_t *csd = ap_get_conn_socket(cs->c);
f4c310fd2555c6faca1f980f00b161eadb089023gstein char dummybuf[2048];
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_size_t nbytes;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct timeout_queue *q;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe q = (cs->pub.state == CONN_STATE_LINGER_SHORT) ? &short_linger_q : &linger_q;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* socket is already in non-blocking state */
f4c310fd2555c6faca1f980f00b161eadb089023gstein do {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe nbytes = sizeof(dummybuf);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rv = apr_socket_recv(csd, dummybuf, &nbytes);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe } while (rv == APR_SUCCESS);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!APR_STATUS_IS_EOF(rv)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_pollset_remove(event_pollset, pfd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_DEBUG_ASSERT(rv == APR_SUCCESS);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_socket_close(csd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_DEBUG_ASSERT(rv == APR_SUCCESS);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_REMOVE(*q, cs);
2889b8817cc73e10884d1944af191e15dcc6cdd4rbb TO_QUEUE_ELEM_INIT(cs);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_clear(cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_push_pool(worker_queue_info, cs->p);
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
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
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void process_timeout_queue(struct timeout_queue *q,
e8f95a682820a599fe41b22977010636be5c2717jim apr_time_t timeout_time,
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe int (*func)(event_conn_state_t *, ap_equeue_t *eq))
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int count = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein event_conn_state_t *first, *cs, *last;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_status_t rv;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!q->count) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe AP_DEBUG_ASSERT(!APR_RING_EMPTY(&q->head, event_conn_state_t, timeout_list));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs = first = APR_RING_FIRST(&q->head);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (cs != APR_RING_SENTINEL(&q->head, event_conn_state_t, timeout_list)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && cs->expiration_time < timeout_time) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe last = cs;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rv = apr_pollset_remove(event_pollset, &cs->pfd);
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");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs = APR_RING_NEXT(cs, timeout_list);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe count++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe if (!count)
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe return;
e8f95a682820a599fe41b22977010636be5c2717jim
1fbf6ba0f5207e6637b49f9a9dfcc779bbe952a9trawick APR_RING_UNSPLICE(first, last, timeout_list);
b6126f9c87296cf2cd10b0a39f7330a9d50e68d7gstein AP_DEBUG_ASSERT(q->count >= count);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe q->count -= count;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (count) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs = APR_RING_NEXT(first, timeout_list);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe TO_QUEUE_ELEM_INIT(first);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe func(first, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe first = cs;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe count--;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe timer_event_t *ep;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe timer_event_t *te;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_status_t rc;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe proc_info *ti = dummy;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int process_slot = ti->pid;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_t *tpool = apr_thread_pool_get(thd);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe void *csd = NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_t *ptrans; /* Pool for per-transaction stuff */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_listen_rec *lr;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int have_idle_worker = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe event_conn_state_t *cs;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const apr_pollfd_t *out_pfd;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_int32_t num = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_interval_time_t timeout_interval;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein apr_time_t timeout_time = 0, now, last_log;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe listener_poll_type *pt;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int closed = 0, listeners_disabled = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe last_log = apr_time_now();
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe free(ti);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* the following times out events that are really close in the future
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * to prevent extra poll calls
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * current value is .1 second
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define TIMEOUT_FUDGE_FACTOR 100000
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define EVENT_FUDGE_FACTOR 10000
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = init_pollset(tpool);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rc != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "failed to initialize pollset, "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "attempting to shutdown process gracefully");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe signal_threads(ST_GRACEFUL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Unblock the signal used to wake this thread up, and set a handler for
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * it.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe unblock_signal(LISTENER_SIGNAL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_signal(LISTENER_SIGNAL, dummy_signal_handler);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (;;) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int workers_were_busy = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (listener_may_exit) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe close_listeners(process_slot, &closed);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (terminate_mode == ST_UNGRACEFUL
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe || apr_atomic_read32(&connection_count) == 0)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (conns_this_child <= 0)
f4c310fd2555c6faca1f980f00b161eadb089023gstein check_infinite_requests();
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein now = apr_time_now();
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe if (APLOGtrace6(ap_server_conf)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* trace log status every second */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (now - last_log > apr_time_from_msec(1000)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe last_log = now;
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)",
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_atomic_read32(&connection_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_read32(&clogged_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe write_completion_q.count,
f4c310fd2555c6faca1f980f00b161eadb089023gstein keepalive_q.count,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_read32(&lingering_count),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_atomic_read32(&suspended_count));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_thread_mutex_lock(g_timer_skiplist_mtx);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe te = apr_skiplist_peek(timer_skiplist);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (te) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (te->when > now) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe timeout_interval = te->when - now;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe timeout_interval = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe timeout_interval = apr_time_from_msec(100);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_mutex_unlock(g_timer_skiplist_mtx);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#if HAVE_SERF
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = serf_context_prerun(g_serf);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rc != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* TOOD: what should do here? ugh. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#endif
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = apr_pollset_poll(event_pollset, timeout_interval, &num, &out_pfd);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rc != APR_SUCCESS
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && !APR_STATUS_IS_EINTR(rc)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && !APR_STATUS_IS_TIMEUP(rc)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_CRIT, rc, ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "apr_pollset_poll failed. Attempting to "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "shutdown process gracefully");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe signal_threads(ST_GRACEFUL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (listener_may_exit) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe close_listeners(process_slot, &closed);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (terminate_mode == ST_UNGRACEFUL
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe || apr_atomic_read32(&connection_count) == 0)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe now = apr_time_now() + EVENT_FUDGE_FACTOR;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_mutex_lock(g_timer_skiplist_mtx);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ep = apr_skiplist_peek(timer_skiplist);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (ep) {
e8f95a682820a599fe41b22977010636be5c2717jim if (ep->when < now) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_skiplist_pop(timer_skiplist, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe push_timer2worker(ep);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ep = apr_skiplist_peek(timer_skiplist);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_mutex_unlock(g_timer_skiplist_mtx);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (num) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pt = (listener_poll_type *) out_pfd->client_data;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (pt->type == PT_CSD) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* one of the sockets is readable */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe struct timeout_queue *remove_from_q = &write_completion_q;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int blocking = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs = (event_conn_state_t *) pt->baton;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe switch (cs->pub.state) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case CONN_STATE_CHECK_REQUEST_LINE_READABLE:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe remove_from_q = &keepalive_q;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* don't wait for a worker for a keepalive request */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe blocking = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* FALL THROUGH */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case CONN_STATE_WRITE_COMPLETION:
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein get_worker(&have_idle_worker, blocking,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe &workers_were_busy);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe TO_QUEUE_REMOVE(*remove_from_q, cs);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rc = apr_pollset_remove(event_pollset, &cs->pfd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
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 */
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");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe start_lingering_close_nonblocking(cs, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein TO_QUEUE_ELEM_INIT(cs);
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.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!have_idle_worker) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe start_lingering_close_nonblocking(cs, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = push2worker(out_pfd, event_pollset);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rc != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_server_conf, "push2worker failed");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein have_idle_worker = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case CONN_STATE_LINGER_NORMAL:
707ecf9559338ec06b24334bc9abcca670325cc4gstein case CONN_STATE_LINGER_SHORT:
707ecf9559338ec06b24334bc9abcca670325cc4gstein process_lingering_close(cs, out_pfd);
707ecf9559338ec06b24334bc9abcca670325cc4gstein break;
707ecf9559338ec06b24334bc9abcca670325cc4gstein default:
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_server_conf,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein "event_loop: unexpected state %d",
707ecf9559338ec06b24334bc9abcca670325cc4gstein cs->pub.state);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_assert(0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else if (pt->type == PT_ACCEPT) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int skip_accept = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int connection_count_local = connection_count;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* A Listener Socket is ready for an accept() */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (workers_were_busy) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein skip_accept = 1;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein "All workers busy, not accepting new conns "
00f73f5096966f34c7db15562e5d2e1233eb4571gstein "in this process");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (listeners_disabled) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein listeners_disabled = 0;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein enable_listensocks(process_slot);
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (connection_count_local > threads_per_child
f4c310fd2555c6faca1f980f00b161eadb089023gstein + ap_queue_info_get_idlers(worker_queue_info) *
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein worker_factor / WORKER_FACTOR_SCALE)
f4c310fd2555c6faca1f980f00b161eadb089023gstein {
707ecf9559338ec06b24334bc9abcca670325cc4gstein skip_accept = 1;
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 connection_count_local);
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
707ecf9559338ec06b24334bc9abcca670325cc4gstein "Idle workers: %u",
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_queue_info_get_idlers(worker_queue_info));
707ecf9559338ec06b24334bc9abcca670325cc4gstein }
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein if (skip_accept == 0) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein lr = (ap_listen_rec *) pt->baton;
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_pop_pool(&ptrans, worker_queue_info);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (ptrans == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* create a new transaction pool for each accepted socket */
707ecf9559338ec06b24334bc9abcca670325cc4gstein apr_allocator_t *allocator;
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_allocator_create(&allocator);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_allocator_max_free_set(allocator,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_max_mem_free);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_create_ex(&ptrans, pconf, NULL, allocator);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_allocator_owner_set(allocator, ptrans);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (ptrans == NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_server_conf,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Failed to create transaction pool");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe signal_threads(ST_GRACEFUL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein }
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein apr_pool_tag(ptrans, "transaction");
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein get_worker(&have_idle_worker, 1, &workers_were_busy);
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = lr->accept_func(&csd, lr, ptrans);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* later we trash rv and rely on csd to indicate
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * success/failure
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe AP_DEBUG_ASSERT(rc == APR_SUCCESS || !csd);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rc == APR_EGENERAL) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* E[NM]FILE, ENOMEM, etc */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein resource_shortage = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein signal_threads(ST_GRACEFUL);
707ecf9559338ec06b24334bc9abcca670325cc4gstein }
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (csd != NULL) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein conns_this_child--;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein rc = ap_queue_push(worker_queue, csd, NULL, ptrans);
707ecf9559338ec06b24334bc9abcca670325cc4gstein if (rc != APR_SUCCESS) {
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* trash the connection; we couldn't queue the connected
707ecf9559338ec06b24334bc9abcca670325cc4gstein * socket to a worker
707ecf9559338ec06b24334bc9abcca670325cc4gstein */
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein apr_socket_close(csd);
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
707ecf9559338ec06b24334bc9abcca670325cc4gstein ap_server_conf,
707ecf9559338ec06b24334bc9abcca670325cc4gstein "ap_queue_push failed");
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein apr_pool_clear(ptrans);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_push_pool(worker_queue_info, ptrans);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein have_idle_worker = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_clear(ptrans);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_push_pool(worker_queue_info, ptrans);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
e8f95a682820a599fe41b22977010636be5c2717jim }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe } /* if:else on pt->type */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if HAVE_SERF
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe else if (pt->type == PT_SERF) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* send socket to serf. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* XXXX: this doesn't require get_worker() */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe serf_event_trigger(g_serf, pt->baton, out_pfd);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein out_pfd++;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm num--;
f4c310fd2555c6faca1f980f00b161eadb089023gstein } /* while for processing poll */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* TODO: break out to separate function */
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_equeue_t *eq = worker_equeues[i];
f4c310fd2555c6faca1f980f00b161eadb089023gstein pollset_op_t *op = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while ((op = ap_equeue_reader_next(eq)) != NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein process_pollop(op);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX possible optimization: stash the current time for use as
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein * r->request_time for new requests
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein now = apr_time_now();
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we only do this once per 0.1s (TIMEOUT_FUDGE_FACTOR) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (now > timeout_time) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein struct process_score *ps;
f4c310fd2555c6faca1f980f00b161eadb089023gstein timeout_time = now + TIMEOUT_FUDGE_FACTOR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* handle timed out sockets */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (workers_were_busy && keepalive_q.count) {
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 keepalive_q.count);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* add in an extra 2sec fudge factor */
f4c310fd2555c6faca1f980f00b161eadb089023gstein process_timeout_queue(&keepalive_q,
f4c310fd2555c6faca1f980f00b161eadb089023gstein timeout_time +
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_server_conf->keep_alive_timeout +
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_time_from_sec(2),
f4c310fd2555c6faca1f980f00b161eadb089023gstein start_lingering_close_nonblocking);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein process_timeout_queue(&keepalive_q, timeout_time,
f4c310fd2555c6faca1f980f00b161eadb089023gstein start_lingering_close_nonblocking);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein /* Step 2: write completion timeouts */
f4c310fd2555c6faca1f980f00b161eadb089023gstein process_timeout_queue(&write_completion_q, timeout_time,
f4c310fd2555c6faca1f980f00b161eadb089023gstein start_lingering_close_nonblocking);
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);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ps = ap_get_scoreboard_process(process_slot);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ps->write_completion = write_completion_q.count;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ps->keep_alive = keepalive_q.count;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ps->connections = apr_atomic_read32(&connection_count);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ps->suspended = apr_atomic_read32(&suspended_count);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein ps->lingering_close = apr_atomic_read32(&lingering_count);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (listeners_disabled && !workers_were_busy &&
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe (int)apr_atomic_read32(&connection_count) <
f4c310fd2555c6faca1f980f00b161eadb089023gstein ((int)ap_queue_info_get_idlers(worker_queue_info) - 1) *
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein worker_factor / WORKER_FACTOR_SCALE + threads_per_child)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe listeners_disabled = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe enable_listensocks(process_slot);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * XXX: do we need to set some timeout that re-enables the listensocks
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * XXX: in case no other event occurs?
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein } /* listener main loop */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe close_listeners(process_slot, &closed);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_queue_term(worker_queue);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_exit(thd, APR_SUCCESS);
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f54da7877f9e092465df38bfda142f3e71dbb7aawrowestatic void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy)
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe{
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe proc_info *ti = dummy;
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe int process_slot = ti->pid;
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe int thread_slot = ti->tid;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_socket_t *csd = NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe event_conn_state_t *cs;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_pool_t *ptrans; /* Pool for per-transaction stuff */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_status_t rv;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int is_idle = 0;
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein timer_event_t *te = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_equeue_t *eq = worker_equeues[thread_slot];
5fbee309625f7a631a42d7dc05bbfa0d45a926ccgstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe free(ti);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein SERVER_STARTING, NULL);
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein while (!workers_may_exit) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!is_idle) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_queue_info_set_idle(worker_queue_info, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
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.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein signal_threads(ST_GRACEFUL);
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein is_idle = 1;
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein }
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein
bbba27074551817d7c6a606c4362965c26a0777egstein ap_update_child_status_from_indexes(process_slot, thread_slot,
bbba27074551817d7c6a606c4362965c26a0777egstein dying ? SERVER_GRACEFUL : SERVER_READY, NULL);
bbba27074551817d7c6a606c4362965c26a0777egstein worker_pop:
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein if (workers_may_exit) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
dd56b1dd453bd9032d97028bc3987f999c31280cwrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein te = NULL;
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein rv = ap_queue_pop_something(worker_queue, &csd, &cs, &ptrans, &te);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein /* We get APR_EOF during a graceful shutdown once all the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * connections accepted by this server process have been handled.
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (APR_STATUS_IS_EOF(rv)) {
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein break;
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein }
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.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
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.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else if (APR_STATUS_IS_EINTR(rv)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe goto worker_pop;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We got some other error. */
dd56b1dd453bd9032d97028bc3987f999c31280cwrowe else if (!workers_may_exit) {
dd56b1dd453bd9032d97028bc3987f999c31280cwrowe ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_pop failed");
872f3bdb13ca15077fbe3a1d560e3c18d7f2e4d1trawick }
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (te != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe te->cbfunc(te->baton);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_thread_mutex_lock(g_timer_skiplist_mtx);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe APR_RING_INSERT_TAIL(&timer_free_ring, te, timer_event_t, link);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_mutex_unlock(g_timer_skiplist_mtx);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
5646ba89a25a695006edae46de226fb57a2e6270gstein is_idle = 0;
5646ba89a25a695006edae46de226fb57a2e6270gstein worker_sockets[thread_slot] = csd;
5646ba89a25a695006edae46de226fb57a2e6270gstein process_socket(thd, ptrans, csd, cs, eq, process_slot, thread_slot);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe worker_sockets[thread_slot] = NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(process_slot, thread_slot,
f4c310fd2555c6faca1f980f00b161eadb089023gstein dying ? SERVER_DEAD :
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe SERVER_GRACEFUL,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe (request_rec *) NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_exit(thd, APR_SUCCESS);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int check_signal(int signum)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe switch (signum) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case SIGTERM:
f4c310fd2555c6faca1f980f00b161eadb089023gstein case SIGINT:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowestatic void create_listener_thread(thread_starter * ts)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein int my_child_num = ts->child_num_arg;
1448efd1befdbe16fe42532edbc379204279aadfasteinmetz apr_threadattr_t *thread_attr = ts->threadattr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein proc_info *my_info;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein my_info = (proc_info *) ap_malloc(sizeof(proc_info));
f4c310fd2555c6faca1f980f00b161eadb089023gstein my_info->pid = my_child_num;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe my_info->tid = -1; /* listener thread doesn't have a thread slot */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe my_info->sd = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,
f4c310fd2555c6faca1f980f00b161eadb089023gstein my_info, pchild);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
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 */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe clean_child_exit(APEXIT_CHILDSICK);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_os_thread_get(&listener_os_thread, ts->listener);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
1448efd1befdbe16fe42532edbc379204279aadfasteinmetz
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
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy)
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein thread_starter *ts = dummy;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_thread_t **threads = ts->threads;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_threadattr_t *thread_attr = ts->threadattr;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein int child_num_arg = ts->child_num_arg;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int my_child_num = child_num_arg;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe proc_info *my_info;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_status_t rv;
066877f1a045103acfdd376d48cdd473c33f409bdougm int i;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int threads_created = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int listener_started = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int loops;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe int prev_threads_created;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int max_recycled_pools = -1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int good_methods[] = {APR_POLLSET_KQUEUE, APR_POLLSET_PORT, APR_POLLSET_EPOLL};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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 if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
bbba27074551817d7c6a606c4362965c26a0777egstein "ap_queue_init() failed");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe clean_child_exit(APEXIT_CHILDFATAL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
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
bbba27074551817d7c6a606c4362965c26a0777egstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe max_recycled_pools = threads_per_child * 3 / 4 ;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe rv = ap_queue_info_create(&worker_queue_info, pchild,
f4c310fd2555c6faca1f980f00b161eadb089023gstein threads_per_child, max_recycled_pools);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_info_create() failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein clean_child_exit(APEXIT_CHILDFATAL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Create the main pollset */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (i = 0; i < sizeof(good_methods) / sizeof(void*); i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_pollset_create_ex(&event_pollset,
066877f1a045103acfdd376d48cdd473c33f409bdougm threads_per_child*2, /* XXX don't we need more, to handle
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * connections in K-A or lingering
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * close?
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pchild, APR_POLLSET_WAKEABLE|APR_POLLSET_NOCOPY|APR_POLLSET_NODEFAULT,
f4c310fd2555c6faca1f980f00b161eadb089023gstein good_methods[i]);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv == APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_pollset_create(&event_pollset,
f4c310fd2555c6faca1f980f00b161eadb089023gstein threads_per_child*2, /* XXX don't we need more, to handle
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein * connections in K-A or lingering
f4c310fd2555c6faca1f980f00b161eadb089023gstein * close?
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein pchild, APR_POLLSET_WAKEABLE|APR_POLLSET_NOCOPY);
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (rv != APR_SUCCESS) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_pollset_create failed; check system or user limits");
f4c310fd2555c6faca1f980f00b161eadb089023gstein clean_child_exit(APEXIT_CHILDFATAL);
e154725591e87e013bad80b6c9aac6f1b0441f7cgstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
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
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein worker_equeues = apr_palloc(pchild, threads_per_child * sizeof(ap_equeue_t*));
02fed5190fb8d69dbb70fb2330526fff85af1c41gstein
67ec15681c83d4f5e119f0742618569017beb3fbstriker for (i = 0; i < threads_per_child; i++) {
bf8de10e1e04cd6019ba4e23ebebcc1eaee5d4bagstein ap_equeue_t* eq = NULL;
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 */
75ba48124689705b1eee2b4fe10fe24a2d2467cdgstein worker_equeues[i] = eq;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
6b745319b1099edacf401e8911efa480440f999agstein
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein loops = prev_threads_created = 0;
066877f1a045103acfdd376d48cdd473c33f409bdougm while (1) {
6b745319b1099edacf401e8911efa480440f999agstein /* threads_per_child does not include the listener thread */
e2308c8c7aadbaa73ea513863b49848e34b99353wrowe for (i = 0; i < threads_per_child; i++) {
6b745319b1099edacf401e8911efa480440f999agstein int status =
6b745319b1099edacf401e8911efa480440f999agstein ap_scoreboard_image->servers[child_num_arg][i].status;
acdb373d92c698a2ac260e03da95816c8a091eb6gstein
acdb373d92c698a2ac260e03da95816c8a091eb6gstein if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
6b745319b1099edacf401e8911efa480440f999agstein continue;
6b745319b1099edacf401e8911efa480440f999agstein }
acdb373d92c698a2ac260e03da95816c8a091eb6gstein
acdb373d92c698a2ac260e03da95816c8a091eb6gstein my_info = (proc_info *) ap_malloc(sizeof(proc_info));
acdb373d92c698a2ac260e03da95816c8a091eb6gstein my_info->pid = my_child_num;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein my_info->tid = i;
6b745319b1099edacf401e8911efa480440f999agstein my_info->sd = 0;
6b745319b1099edacf401e8911efa480440f999agstein
6b745319b1099edacf401e8911efa480440f999agstein /* We are creating threads right now */
dd56b1dd453bd9032d97028bc3987f999c31280cwrowe ap_update_child_status_from_indexes(my_child_num, i,
6b745319b1099edacf401e8911efa480440f999agstein SERVER_STARTING, NULL);
acdb373d92c698a2ac260e03da95816c8a091eb6gstein /* We let each thread update its own scoreboard entry. This is
acdb373d92c698a2ac260e03da95816c8a091eb6gstein * done because it lets us deal with tid better.
acdb373d92c698a2ac260e03da95816c8a091eb6gstein */
acdb373d92c698a2ac260e03da95816c8a091eb6gstein rv = apr_thread_create(&threads[i], thread_attr,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein worker_thread, my_info, pchild);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (rv != APR_SUCCESS) {
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 */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe clean_child_exit(APEXIT_CHILDSICK);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe threads_created++;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein }
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* Start the listener only when there are workers available */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!listener_started && threads_created) {
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein create_listener_thread(ts);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe listener_started = 1;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (start_thread_may_exit || threads_created == threads_per_child) {
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein break;
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein }
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* wait for previous generation to clean up an entry */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein apr_sleep(apr_time_from_sec(1));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ++loops;
e2308c8c7aadbaa73ea513863b49848e34b99353wrowe if (loops % 120 == 0) { /* every couple of minutes */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein if (prev_threads_created == threads_created) {
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
6b745319b1099edacf401e8911efa480440f999agstein "child %" APR_PID_T_FMT " isn't taking over "
6b745319b1099edacf401e8911efa480440f999agstein "slots very quickly (%d of %d)",
5a47cad1aef57039cd47eb34ebbc2959c610f326gstein ap_my_pid, threads_created,
75ba48124689705b1eee2b4fe10fe24a2d2467cdgstein threads_per_child);
5a47cad1aef57039cd47eb34ebbc2959c610f326gstein }
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein prev_threads_created = threads_created;
5a47cad1aef57039cd47eb34ebbc2959c610f326gstein }
5a47cad1aef57039cd47eb34ebbc2959c610f326gstein }
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein
75ba48124689705b1eee2b4fe10fe24a2d2467cdgstein /* What state should this child_main process be listed as in the
* scoreboard...?
* ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
* (request_rec *) NULL);
*
* This state should be listed separately in the scoreboard, in some kind
* of process_status, not mixed in with the worker threads' status.
* "life_status" is almost right, but it's in the worker's structure, and
* the name could be clearer. gla
*/
apr_thread_exit(thd, APR_SUCCESS);
return NULL;
}
static void join_workers(apr_thread_t * listener, apr_thread_t ** threads)
{
int i;
apr_status_t rv, thread_rv;
if (listener) {
int iter;
/* deal with a rare timing window which affects waking up the
* listener thread... if the signal sent to the listener thread
* is delivered between the time it verifies that the
* listener_may_exit flag is clear and the time it enters a
* blocking syscall, the signal didn't do any good... work around
* that by sleeping briefly and sending it again
*/
iter = 0;
while (iter < 10 && !dying) {
/* listener has not stopped accepting yet */
apr_sleep(apr_time_make(0, 500000));
wakeup_listener();
++iter;
}
if (iter >= 10) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00475)
"the listener thread didn't stop accepting");
}
else {
rv = apr_thread_join(&thread_rv, listener);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00476)
"apr_thread_join: unable to join listener thread");
}
}
}
for (i = 0; i < threads_per_child; i++) {
if (threads[i]) { /* if we ever created this thread */
rv = apr_thread_join(&thread_rv, threads[i]);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00477)
"apr_thread_join: unable to join worker "
"thread %d", i);
}
}
}
}
static void join_start_thread(apr_thread_t * start_thread_id)
{
apr_status_t rv, thread_rv;
start_thread_may_exit = 1; /* tell it to give up in case it is still
* trying to take over slots from a
* previous generation
*/
rv = apr_thread_join(&thread_rv, start_thread_id);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00478)
"apr_thread_join: unable to join the start " "thread");
}
}
static void child_main(int child_num_arg)
{
apr_thread_t **threads;
apr_status_t rv;
thread_starter *ts;
apr_threadattr_t *thread_attr;
apr_thread_t *start_thread_id;
apr_pool_t *pskip;
int i;
ap_listen_rec *lr;
mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
* child initializes
*/
ap_my_pid = getpid();
ap_fatal_signal_child_setup(ap_server_conf);
apr_pool_create(&pchild, pconf);
/* close unused listeners and pods */
for (i = 0; i < num_buckets; i++) {
if (i != bucket[child_num_arg]) {
lr = mpm_listen[i];
while(lr) {
apr_socket_close(lr->sd);
lr = lr->next;
}
mpm_listen[i]->active = 0;
ap_mpm_podx_close(pod[i]);
}
}
/*stuff to do before we switch id's, so we have permissions. */
ap_reopen_scoreboard(pchild, NULL, 0);
if (ap_run_drop_privileges(pchild, ap_server_conf)) {
clean_child_exit(APEXIT_CHILDFATAL);
}
apr_thread_mutex_create(&g_timer_skiplist_mtx, APR_THREAD_MUTEX_DEFAULT, pchild);
APR_RING_INIT(&timer_free_ring, timer_event_t, link);
apr_pool_create(&pskip, pchild);
apr_skiplist_init(&timer_skiplist, pskip);
apr_skiplist_set_compare(timer_skiplist, indexing_comp, indexing_compk);
ap_run_child_init(pchild, ap_server_conf);
/* done with init critical section */
/* Just use the standard apr_setup_signal_thread to block all signals
* from being received. The child processes no longer use signals for
* any communication with the parent process.
*/
rv = apr_setup_signal_thread();
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, APLOGNO(00479)
"Couldn't initialize signal thread");
clean_child_exit(APEXIT_CHILDFATAL);
}
if (ap_max_requests_per_child) {
conns_this_child = ap_max_requests_per_child;
}
else {
/* coding a value of zero means infinity */
conns_this_child = APR_INT32_MAX;
}
/* Setup worker threads */
/* clear the storage; we may not create all our threads immediately,
* and we want a 0 entry to indicate a thread which was not created
*/
threads = ap_calloc(threads_per_child, sizeof(apr_thread_t *));
ts = apr_palloc(pchild, sizeof(*ts));
apr_threadattr_create(&thread_attr, pchild);
/* 0 means PTHREAD_CREATE_JOINABLE */
apr_threadattr_detach_set(thread_attr, 0);
if (ap_thread_stacksize != 0) {
rv = apr_threadattr_stacksize_set(thread_attr, ap_thread_stacksize);
if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(02436)
"WARNING: ThreadStackSize of %" APR_SIZE_T_FMT " is "
"inappropriate, using default",
ap_thread_stacksize);
}
}
ts->threads = threads;
ts->listener = NULL;
ts->child_num_arg = child_num_arg;
ts->threadattr = thread_attr;
rv = apr_thread_create(&start_thread_id, thread_attr, start_threads,
ts, pchild);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(00480)
"apr_thread_create: unable to create worker thread");
/* let the parent decide how bad this really is */
clean_child_exit(APEXIT_CHILDSICK);
}
mpm_state = AP_MPMQ_RUNNING;
/* If we are only running in one_process mode, we will want to
* still handle signals. */
if (one_process) {
/* Block until we get a terminating signal. */
apr_signal_thread(check_signal);
/* make sure the start thread has finished; signal_threads()
* and join_workers() depend on that
*/
/* XXX join_start_thread() won't be awakened if one of our
* threads encounters a critical error and attempts to
* shutdown this child
*/
join_start_thread(start_thread_id);
/* helps us terminate a little more quickly than the dispatch of the
* signal thread; beats the Pipe of Death and the browsers
*/
signal_threads(ST_UNGRACEFUL);
/* A terminating signal was received. Now join each of the
* workers to clean them up.
* If the worker already exited, then the join frees
* their resources and returns.
* If the worker hasn't exited, then this blocks until
* they have (then cleans up).
*/
join_workers(ts->listener, threads);
}
else { /* !one_process */
/* remove SIGTERM from the set of blocked signals... if one of
* the other threads in the process needs to take us down
* (e.g., for MaxConnectionsPerChild) it will send us SIGTERM
*/
unblock_signal(SIGTERM);
apr_signal(SIGTERM, dummy_signal_handler);
/* Watch for any messages from the parent over the POD */
while (1) {
rv = ap_mpm_podx_check(child_pod);
if (rv == AP_MPM_PODX_NORESTART) {
/* see if termination was triggered while we slept */
switch (terminate_mode) {
case ST_GRACEFUL:
rv = AP_MPM_PODX_GRACEFUL;
break;
case ST_UNGRACEFUL:
rv = AP_MPM_PODX_RESTART;
break;
}
}
if (rv == AP_MPM_PODX_GRACEFUL || rv == AP_MPM_PODX_RESTART) {
/* make sure the start thread has finished;
* signal_threads() and join_workers depend on that
*/
join_start_thread(start_thread_id);
signal_threads(rv ==
AP_MPM_PODX_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL);
break;
}
}
/* A terminating signal was received. Now join each of the
* workers to clean them up.
* If the worker already exited, then the join frees
* their resources and returns.
* If the worker hasn't exited, then this blocks until
* they have (then cleans up).
*/
join_workers(ts->listener, threads);
}
free(threads);
clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);
}
static int make_child(server_rec * s, int slot)
{
int pid;
if (slot + 1 > retained->max_daemons_limit) {
retained->max_daemons_limit = slot + 1;
}
child_listen = mpm_listen[bucket[slot]];
child_pod = pod[bucket[slot]];
if (one_process) {
set_signals();
event_note_child_started(slot, getpid());
child_main(slot);
/* NOTREACHED */
}
if ((pid = fork()) == -1) {
ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, APLOGNO(00481)
"fork: Unable to fork new process");
/* fork didn't succeed. There's no need to touch the scoreboard;
* if we were trying to replace a failed child process, then
* server_main_loop() marked its workers SERVER_DEAD, and if
* we were trying to replace a child process that exited normally,
* its worker_thread()s left SERVER_DEAD or SERVER_GRACEFUL behind.
*/
/* In case system resources are maxxed out, we don't want
Apache running away with the CPU trying to fork over and
over and over again. */
apr_sleep(apr_time_from_sec(10));
return -1;
}
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
/* By default, AIX binds to a single processor. This bit unbinds
* children which will then bind to another CPU.
*/
int status = bindprocessor(BINDPROCESS, (int) getpid(),
PROCESSOR_CLASS_ANY);
if (status != OK)
ap_log_error(APLOG_MARK, APLOG_DEBUG, errno,
ap_server_conf, APLOGNO(00482)
"processor unbind failed");
#endif
RAISE_SIGSTOP(MAKE_CHILD);
apr_signal(SIGTERM, just_die);
child_main(slot);
/* NOTREACHED */
}
/* else */
if (ap_scoreboard_image->parent[slot].pid != 0) {
/* This new child process is squatting on the scoreboard
* entry owned by an exiting child process, which cannot
* exit until all active requests complete.
*/
event_note_child_lost_slot(slot, pid);
}
ap_scoreboard_image->parent[slot].quiescing = 0;
ap_scoreboard_image->parent[slot].not_accepting = 0;
event_note_child_started(slot, pid);
return 0;
}
/* start up a bunch of children */
static void startup_children(int number_to_start)
{
int i;
for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
if (ap_scoreboard_image->parent[i].pid != 0) {
continue;
}
bucket[i] = i % num_buckets;
if (make_child(ap_server_conf, i) < 0) {
break;
}
--number_to_start;
}
}
static void perform_idle_server_maintenance(int child_bucket)
{
int i, j;
int idle_thread_count;
worker_score *ws;
process_score *ps;
int free_length;
int totally_free_length = 0;
int free_slots[MAX_SPAWN_RATE];
int last_non_dead;
int total_non_dead;
int active_thread_count = 0;
/* initialize the free_list */
free_length = 0;
idle_thread_count = 0;
last_non_dead = -1;
total_non_dead = 0;
for (i = 0; i < ap_daemons_limit; ++i) {
/* Initialization to satisfy the compiler. It doesn't know
* that threads_per_child is always > 0 */
int status = SERVER_DEAD;
int any_dying_threads = 0;
int any_dead_threads = 0;
int all_dead_threads = 1;
int child_threads_active = 0;
if (i >= retained->max_daemons_limit
&& totally_free_length == retained->idle_spawn_rate[child_bucket])
/* short cut if all active processes have been examined and
* enough empty scoreboard slots have been found
*/
break;
ps = &ap_scoreboard_image->parent[i];
for (j = 0; j < threads_per_child; j++) {
ws = &ap_scoreboard_image->servers[i][j];
status = ws->status;
/* XXX any_dying_threads is probably no longer needed GLA */
any_dying_threads = any_dying_threads ||
(status == SERVER_GRACEFUL);
any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
all_dead_threads = all_dead_threads &&
(status == SERVER_DEAD || status == SERVER_GRACEFUL);
/* We consider a starting server as idle because we started it
* at least a cycle ago, and if it still hasn't finished starting
* then we're just going to swamp things worse by forking more.
* So we hopefully won't need to fork more if we count it.
* This depends on the ordering of SERVER_READY and SERVER_STARTING.
*/
if (ps->pid != 0) { /* XXX just set all_dead_threads in outer
for loop if no pid? not much else matters */
if (status <= SERVER_READY && !ps->quiescing && !ps->not_accepting
&& ps->generation == retained->my_generation &&
bucket[i] == child_bucket)
{
++idle_thread_count;
}
if (status >= SERVER_READY && status < SERVER_GRACEFUL) {
++child_threads_active;
}
}
}
active_thread_count += child_threads_active;
if (any_dead_threads
&& totally_free_length < retained->idle_spawn_rate[child_bucket]
&& free_length < MAX_SPAWN_RATE/num_buckets
&& (!ps->pid /* no process in the slot */
|| ps->quiescing)) { /* or at least one is going away */
if (all_dead_threads) {
/* great! we prefer these, because the new process can
* start more threads sooner. So prioritize this slot
* by putting it ahead of any slots with active threads.
*
* first, make room by moving a slot that's potentially still
* in use to the end of the array
*/
free_slots[free_length] = free_slots[totally_free_length];
free_slots[totally_free_length++] = i;
}
else {
/* slot is still in use - back of the bus
*/
free_slots[free_length] = i;
}
++free_length;
}
else if (child_threads_active == threads_per_child) {
had_healthy_child = 1;
}
/* XXX if (!ps->quiescing) is probably more reliable GLA */
if (!any_dying_threads) {
last_non_dead = i;
++total_non_dead;
}
}
if (retained->sick_child_detected) {
if (had_healthy_child) {
/* Assume this is a transient error, even though it may not be. Leave
* the server up in case it is able to serve some requests or the
* problem will be resolved.
*/
retained->sick_child_detected = 0;
}
else {
/* looks like a basket case, as no child ever fully initialized; give up.
*/
shutdown_pending = 1;
child_fatal = 1;
ap_log_error(APLOG_MARK, APLOG_ALERT, 0,
ap_server_conf, APLOGNO(00483)
"No active workers found..."
" Apache is exiting!");
/* the child already logged the failure details */
return;
}
}
retained->max_daemons_limit = last_non_dead + 1;
if (idle_thread_count > max_spare_threads/num_buckets) {
/* Kill off one child */
ap_mpm_podx_signal(pod[child_bucket], AP_MPM_PODX_GRACEFUL);
retained->idle_spawn_rate[child_bucket] = 1;
}
else if (idle_thread_count < min_spare_threads/num_buckets) {
/* terminate the free list */
if (free_length == 0) { /* scoreboard is full, can't fork */
if (active_thread_count >= ap_daemons_limit * threads_per_child) {
if (!retained->maxclients_reported) {
/* only report this condition once */
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(00484)
"server reached MaxRequestWorkers setting, "
"consider raising the MaxRequestWorkers "
"setting");
retained->maxclients_reported = 1;
}
}
else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(00485)
"scoreboard is full, not at MaxRequestWorkers");
}
retained->idle_spawn_rate[child_bucket] = 1;
}
else {
if (free_length > retained->idle_spawn_rate[child_bucket]) {
free_length = retained->idle_spawn_rate[child_bucket];
}
if (retained->idle_spawn_rate[child_bucket] >= 8) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00486)
"server seems busy, (you may need "
"to increase StartServers, ThreadsPerChild "
"or Min/MaxSpareThreads), "
"spawning %d children, there are around %d idle "
"threads, and %d total children", free_length,
idle_thread_count, total_non_dead);
}
for (i = 0; i < free_length; ++i) {
bucket[free_slots[i]] = child_bucket;
make_child(ap_server_conf, free_slots[i]);
}
/* the next time around we want to spawn twice as many if this
* wasn't good enough, but not if we've just done a graceful
*/
if (retained->hold_off_on_exponential_spawning) {
--retained->hold_off_on_exponential_spawning;
}
else if (retained->idle_spawn_rate[child_bucket] < MAX_SPAWN_RATE/num_buckets) {
retained->idle_spawn_rate[child_bucket] *= 2;
}
}
}
else {
retained->idle_spawn_rate[child_bucket] = 1;
}
}
static void server_main_loop(int remaining_children_to_start)
{
ap_generation_t old_gen;
int child_slot;
apr_exit_why_e exitwhy;
int status, processed_status;
apr_proc_t pid;
int i;
while (!restart_pending && !shutdown_pending) {
ap_wait_or_timeout(&exitwhy, &status, &pid, pconf, ap_server_conf);
if (pid.pid != -1) {
processed_status = ap_process_child_status(&pid, exitwhy, status);
child_slot = ap_find_child_by_pid(&pid);
if (processed_status == APEXIT_CHILDFATAL) {
/* fix race condition found in PR 39311
* A child created at the same time as a graceful happens
* can find the lock missing and create a fatal error.
* It is not fatal for the last generation to be in this state.
*/
if (child_slot < 0
|| ap_get_scoreboard_process(child_slot)->generation
== retained->my_generation) {
shutdown_pending = 1;
child_fatal = 1;
return;
}
else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, APLOGNO(00487)
"Ignoring fatal error in child of previous "
"generation (pid %ld).",
(long)pid.pid);
retained->sick_child_detected = 1;
}
}
else if (processed_status == APEXIT_CHILDSICK) {
/* tell perform_idle_server_maintenance to check into this
* on the next timer pop
*/
retained->sick_child_detected = 1;
}
/* non-fatal death... note that it's gone in the scoreboard. */
if (child_slot >= 0) {
for (i = 0; i < threads_per_child; i++)
ap_update_child_status_from_indexes(child_slot, i,
SERVER_DEAD,
(request_rec *) NULL);
event_note_child_killed(child_slot, 0, 0);
ap_scoreboard_image->parent[child_slot].quiescing = 0;
if (processed_status == APEXIT_CHILDSICK) {
/* resource shortage, minimize the fork rate */
retained->idle_spawn_rate[bucket[child_slot]] = 1;
}
else if (remaining_children_to_start
&& child_slot < ap_daemons_limit) {
/* we're still doing a 1-for-1 replacement of dead
* children with new children
*/
make_child(ap_server_conf, child_slot);
--remaining_children_to_start;
}
}
else if (ap_unregister_extra_mpm_process(pid.pid, &old_gen) == 1) {
event_note_child_killed(-1, /* already out of the scoreboard */
pid.pid, old_gen);
if (processed_status == APEXIT_CHILDSICK
&& old_gen == retained->my_generation) {
/* resource shortage, minimize the fork rate */
for (i = 0; i < num_buckets; i++) {
retained->idle_spawn_rate[i] = 1;
}
}
#if APR_HAS_OTHER_CHILD
}
else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
status) == 0) {
/* handled */
#endif
}
else if (retained->is_graceful) {
/* Great, we've probably just lost a slot in the
* scoreboard. Somehow we don't know about this child.
*/
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
ap_server_conf, APLOGNO(00488)
"long lost child came home! (pid %ld)",
(long) pid.pid);
}
/* Don't perform idle maintenance when a child dies,
* only do it when there's a timeout. Remember only a
* finite number of children can die, and it's pretty
* pathological for a lot to die suddenly.
*/
continue;
}
else if (remaining_children_to_start) {
/* we hit a 1 second timeout in which none of the previous
* generation of children needed to be reaped... so assume
* they're all done, and pick up the slack if any is left.
*/
startup_children(remaining_children_to_start);
remaining_children_to_start = 0;
/* In any event we really shouldn't do the code below because
* few of the servers we just started are in the IDLE state
* yet, so we'd mistakenly create an extra server.
*/
continue;
}
for (i = 0; i < num_buckets; i++) {
perform_idle_server_maintenance(i);
}
}
}
static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
{
int remaining_children_to_start;
int i;
ap_log_pid(pconf, ap_pid_fname);
if (!retained->is_graceful) {
if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
mpm_state = AP_MPMQ_STOPPING;
return DONE;
}
/* fix the generation number in the global score; we just got a new,
* cleared scoreboard
*/
ap_scoreboard_image->global->running_generation = retained->my_generation;
}
bucket = apr_palloc(_pconf, sizeof(int) * ap_daemons_limit);
restart_pending = shutdown_pending = 0;
set_signals();
/* Don't thrash... */
if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets)
max_spare_threads = min_spare_threads + threads_per_child * num_buckets;
/* If we're doing a graceful_restart then we're going to see a lot
* of children exiting immediately when we get into the main loop
* below (because we just sent them AP_SIG_GRACEFUL). This happens pretty
* rapidly... and for each one that exits we may start a new one, until
* there are at least min_spare_threads idle threads, counting across
* all children. But we may be permitted to start more children than
* that, so we'll just keep track of how many we're
* supposed to start up without the 1 second penalty between each fork.
*/
remaining_children_to_start = ap_daemons_to_start;
if (remaining_children_to_start > ap_daemons_limit) {
remaining_children_to_start = ap_daemons_limit;
}
if (!retained->is_graceful) {
startup_children(remaining_children_to_start);
remaining_children_to_start = 0;
}
else {
/* give the system some time to recover before kicking into
* exponential mode */
retained->hold_off_on_exponential_spawning = 10;
}
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00489)
"%s configured -- resuming normal operations",
ap_get_server_description());
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00490)
"Server built: %s", ap_get_server_built());
ap_log_command_line(plog, s);
ap_log_common(s);
mpm_state = AP_MPMQ_RUNNING;
server_main_loop(remaining_children_to_start);
mpm_state = AP_MPMQ_STOPPING;
if (shutdown_pending && !retained->is_graceful) {
/* Time to shut down:
* Kill child processes, tell them to call child_exit, etc...
*/
for (i = 0; i < num_buckets; i++) {
ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
}
ap_reclaim_child_processes(1, /* Start with SIGTERM */
event_note_child_killed);
if (!child_fatal) {
/* cleanup pid file on normal shutdown */
ap_remove_pid(pconf, ap_pid_fname);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
ap_server_conf, APLOGNO(00491) "caught SIGTERM, shutting down");
}
return DONE;
} else if (shutdown_pending) {
/* Time to gracefully shut down:
* Kill child processes, tell them to call child_exit, etc...
*/
int active_children;
int index;
apr_time_t cutoff = 0;
/* Close our listeners, and then ask our children to do same */
ap_close_listeners();
for (i = 0; i < num_buckets; i++) {
ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
}
ap_relieve_child_processes(event_note_child_killed);
if (!child_fatal) {
/* cleanup pid file on normal shutdown */
ap_remove_pid(pconf, ap_pid_fname);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00492)
"caught " AP_SIG_GRACEFUL_STOP_STRING
", shutting down gracefully");
}
if (ap_graceful_shutdown_timeout) {
cutoff = apr_time_now() +
apr_time_from_sec(ap_graceful_shutdown_timeout);
}
/* Don't really exit until each child has finished */
shutdown_pending = 0;
do {
/* Pause for a second */
apr_sleep(apr_time_from_sec(1));
/* Relieve any children which have now exited */
ap_relieve_child_processes(event_note_child_killed);
active_children = 0;
for (index = 0; index < ap_daemons_limit; ++index) {
if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
active_children = 1;
/* Having just one child is enough to stay around */
break;
}
}
} while (!shutdown_pending && active_children &&
(!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
/* We might be here because we received SIGTERM, either
* way, try and make sure that all of our processes are
* really dead.
*/
for (i = 0; i < num_buckets; i++) {
ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
}
ap_reclaim_child_processes(1, event_note_child_killed);
return DONE;
}
/* we've been told to restart */
apr_signal(SIGHUP, SIG_IGN);
if (one_process) {
/* not worth thinking about */
return DONE;
}
/* advance to the next generation */
/* XXX: we really need to make sure this new generation number isn't in
* use by any of the children.
*/
++retained->my_generation;
ap_scoreboard_image->global->running_generation = retained->my_generation;
if (retained->is_graceful) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00493)
AP_SIG_GRACEFUL_STRING
" received. Doing graceful restart");
/* wake up the children...time to die. But we'll have more soon */
for (i = 0; i < num_buckets; i++) {
ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
}
/* This is mostly for debugging... so that we know what is still
* gracefully dealing with existing request.
*/
}
else {
/* Kill 'em all. Since the child acts the same on the parents SIGTERM
* and a SIGHUP, we may as well use the same signal, because some user
* pthreads are stealing signals from us left and right.
*/
for (i = 0; i < num_buckets; i++) {
ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
}
ap_reclaim_child_processes(1, /* Start with SIGTERM */
event_note_child_killed);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00494)
"SIGHUP received. Attempting to restart");
}
return OK;
}
/* This really should be a post_config hook, but the error log is already
* redirected by that point, so we need to do this in the open_logs phase.
*/
static int event_open_logs(apr_pool_t * p, apr_pool_t * plog,
apr_pool_t * ptemp, server_rec * s)
{
int startup = 0;
int level_flags = 0;
apr_status_t rv;
int i;
int num_of_cores = 0;
pconf = p;
/* the reverse of pre_config, we want this only the first time around */
if (retained->module_loads == 1) {
startup = 1;
level_flags |= APLOG_STARTUP;
}
enable_default_listener = 0;
if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
(startup ? NULL : s),
"no listening sockets available, shutting down");
return DONE;
}
enable_default_listener = 1;
if (have_so_reuseport) {
#ifdef _SC_NPROCESSORS_ONLN
num_of_cores = sysconf(_SC_NPROCESSORS_ONLN);
#else
num_of_cores = 1;
#endif
if (num_of_cores > 8) {
num_buckets = num_of_cores/8;
}
else {
num_buckets = 1;
}
}
else {
num_buckets = 1;
}
ap_duplicate_listeners(ap_server_conf, pconf, num_buckets);
pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
if (!one_process) {
for (i = 0; i < num_buckets; i++) {
if ((rv = ap_mpm_podx_open(pconf, &pod[i]))) {
ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
(startup ? NULL : s),
"could not open pipe-of-death");
return DONE;
}
}
}
/* for skiplist */
srand((unsigned int)apr_time_now());
return OK;
}
static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog,
apr_pool_t * ptemp)
{
int no_detach, debug, foreground;
apr_status_t rv;
const char *userdata_key = "mpm_eventopt_module";
int i;
mpm_state = AP_MPMQ_STARTING;
debug = ap_exists_config_define("DEBUG");
if (debug) {
foreground = one_process = 1;
no_detach = 0;
}
else {
one_process = ap_exists_config_define("ONE_PROCESS");
no_detach = ap_exists_config_define("NO_DETACH");
foreground = ap_exists_config_define("FOREGROUND");
}
/* sigh, want this only the second time around */
retained = ap_retained_data_get(userdata_key);
if (!retained) {
retained = ap_retained_data_create(userdata_key, sizeof(*retained));
retained->max_daemons_limit = -1;
}
++retained->module_loads;
if (retained->module_loads == 2) {
/* test for correct operation of fdqueue */
static apr_uint32_t foo1, foo2;
apr_atomic_set32(&foo1, 100);
foo2 = apr_atomic_add32(&foo1, -10);
if (foo2 != 100 || foo1 != 90) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(02406)
"atomics not working as expected - add32 of negative number");
return HTTP_INTERNAL_SERVER_ERROR;
}
retained->idle_spawn_rate = apr_palloc(pconf, sizeof(int) * num_buckets);
for (i = 0; i< num_buckets; i++) {
retained->idle_spawn_rate[i] = 1;
}
rv = apr_pollset_create(&event_pollset, 1, plog,
APR_POLLSET_WAKEABLE|APR_POLLSET_NOCOPY);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00495)
"apr_pollset_create failed; check system or user limits");
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_pollset_destroy(event_pollset);
if (!one_process && !foreground) {
/* before we detach, setup crash handlers to log to errorlog */
ap_fatal_signal_setup(ap_server_conf, pconf);
rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
: APR_PROC_DETACH_DAEMONIZE);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00496)
"apr_proc_detach failed");
return HTTP_INTERNAL_SERVER_ERROR;
}
}
}
parent_pid = ap_my_pid = getpid();
ap_listen_pre_config();
ap_daemons_to_start = DEFAULT_START_DAEMON;
min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
server_limit = DEFAULT_SERVER_LIMIT;
thread_limit = DEFAULT_THREAD_LIMIT;
ap_daemons_limit = server_limit;
threads_per_child = DEFAULT_THREADS_PER_CHILD;
max_workers = ap_daemons_limit * threads_per_child;
had_healthy_child = 0;
ap_extended_status = 0;
return OK;
}
static int event_check_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
int startup = 0;
/* the reverse of pre_config, we want this only the first time around */
if (retained->module_loads == 1) {
startup = 1;
}
if (server_limit > MAX_SERVER_LIMIT) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00497)
"WARNING: ServerLimit of %d exceeds compile-time "
"limit of", server_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" %d servers, decreasing to %d.",
MAX_SERVER_LIMIT, MAX_SERVER_LIMIT);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00498)
"ServerLimit of %d exceeds compile-time limit "
"of %d, decreasing to match",
server_limit, MAX_SERVER_LIMIT);
}
server_limit = MAX_SERVER_LIMIT;
}
else if (server_limit < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00499)
"WARNING: ServerLimit of %d not allowed, "
"increasing to 1.", server_limit);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00500)
"ServerLimit of %d not allowed, increasing to 1",
server_limit);
}
server_limit = 1;
}
/* you cannot change ServerLimit across a restart; ignore
* any such attempts
*/
if (!retained->first_server_limit) {
retained->first_server_limit = server_limit;
}
else if (server_limit != retained->first_server_limit) {
/* don't need a startup console version here */
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00501)
"changing ServerLimit to %d from original value of %d "
"not allowed during restart",
server_limit, retained->first_server_limit);
server_limit = retained->first_server_limit;
}
if (thread_limit > MAX_THREAD_LIMIT) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00502)
"WARNING: ThreadLimit of %d exceeds compile-time "
"limit of", thread_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" %d threads, decreasing to %d.",
MAX_THREAD_LIMIT, MAX_THREAD_LIMIT);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00503)
"ThreadLimit of %d exceeds compile-time limit "
"of %d, decreasing to match",
thread_limit, MAX_THREAD_LIMIT);
}
thread_limit = MAX_THREAD_LIMIT;
}
else if (thread_limit < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00504)
"WARNING: ThreadLimit of %d not allowed, "
"increasing to 1.", thread_limit);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00505)
"ThreadLimit of %d not allowed, increasing to 1",
thread_limit);
}
thread_limit = 1;
}
/* you cannot change ThreadLimit across a restart; ignore
* any such attempts
*/
if (!retained->first_thread_limit) {
retained->first_thread_limit = thread_limit;
}
else if (thread_limit != retained->first_thread_limit) {
/* don't need a startup console version here */
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00506)
"changing ThreadLimit to %d from original value of %d "
"not allowed during restart",
thread_limit, retained->first_thread_limit);
thread_limit = retained->first_thread_limit;
}
if (threads_per_child > thread_limit) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00507)
"WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
"of", threads_per_child);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" %d threads, decreasing to %d.",
thread_limit, thread_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" To increase, please see the ThreadLimit "
"directive.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00508)
"ThreadsPerChild of %d exceeds ThreadLimit "
"of %d, decreasing to match",
threads_per_child, thread_limit);
}
threads_per_child = thread_limit;
}
else if (threads_per_child < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00509)
"WARNING: ThreadsPerChild of %d not allowed, "
"increasing to 1.", threads_per_child);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00510)
"ThreadsPerChild of %d not allowed, increasing to 1",
threads_per_child);
}
threads_per_child = 1;
}
if (max_workers < threads_per_child) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00511)
"WARNING: MaxRequestWorkers of %d is less than "
"ThreadsPerChild of", max_workers);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" %d, increasing to %d. MaxRequestWorkers must be at "
"least as large",
threads_per_child, threads_per_child);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" as the number of threads in a single server.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00512)
"MaxRequestWorkers of %d is less than ThreadsPerChild "
"of %d, increasing to match",
max_workers, threads_per_child);
}
max_workers = threads_per_child;
}
ap_daemons_limit = max_workers / threads_per_child;
if (max_workers % threads_per_child) {
int tmp_max_workers = ap_daemons_limit * threads_per_child;
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00513)
"WARNING: MaxRequestWorkers of %d is not an integer "
"multiple of", max_workers);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" ThreadsPerChild of %d, decreasing to nearest "
"multiple %d,", threads_per_child,
tmp_max_workers);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" for a maximum of %d servers.",
ap_daemons_limit);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00514)
"MaxRequestWorkers of %d is not an integer multiple "
"of ThreadsPerChild of %d, decreasing to nearest "
"multiple %d", max_workers, threads_per_child,
tmp_max_workers);
}
max_workers = tmp_max_workers;
}
if (ap_daemons_limit > server_limit) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00515)
"WARNING: MaxRequestWorkers of %d would require %d "
"servers and ", max_workers, ap_daemons_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" would exceed ServerLimit of %d, decreasing to %d.",
server_limit, server_limit * threads_per_child);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" To increase, please see the ServerLimit "
"directive.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00516)
"MaxRequestWorkers of %d would require %d servers and "
"exceed ServerLimit of %d, decreasing to %d",
max_workers, ap_daemons_limit, server_limit,
server_limit * threads_per_child);
}
ap_daemons_limit = server_limit;
}
/* ap_daemons_to_start > ap_daemons_limit checked in ap_mpm_run() */
if (ap_daemons_to_start < 0) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00517)
"WARNING: StartServers of %d not allowed, "
"increasing to 1.", ap_daemons_to_start);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00518)
"StartServers of %d not allowed, increasing to 1",
ap_daemons_to_start);
}
ap_daemons_to_start = 1;
}
if (min_spare_threads < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00519)
"WARNING: MinSpareThreads of %d not allowed, "
"increasing to 1", min_spare_threads);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" to avoid almost certain server failure.");
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" Please read the documentation.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00520)
"MinSpareThreads of %d not allowed, increasing to 1",
min_spare_threads);
}
min_spare_threads = 1;
}
/* max_spare_threads < min_spare_threads + threads_per_child
* checked in ap_mpm_run()
*/
return OK;
}
static void event_hooks(apr_pool_t * p)
{
/* Our open_logs hook function must run before the core's, or stderr
* will be redirected to a file, and the messages won't print to the
* console.
*/
static const char *const aszSucc[] = { "core.c", NULL };
one_process = 0;
ap_force_set_tz(p);
ap_hook_open_logs(event_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
/* we need to set the MPM state before other pre-config hooks use MPM query
* to retrieve it, so register as REALLY_FIRST
*/
ap_hook_pre_config(event_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
ap_hook_check_config(event_check_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm(event_run, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_query(event_query, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_register_timed_callback(event_register_timed_callback, NULL, NULL,
APR_HOOK_MIDDLE);
ap_hook_mpm_get_name(event_get_name, NULL, NULL, APR_HOOK_MIDDLE);
}
static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
ap_daemons_to_start = atoi(arg);
return NULL;
}
static const char *set_min_spare_threads(cmd_parms * cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
min_spare_threads = atoi(arg);
return NULL;
}
static const char *set_max_spare_threads(cmd_parms * cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
max_spare_threads = atoi(arg);
return NULL;
}
static const char *set_max_workers(cmd_parms * cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
if (!strcasecmp(cmd->cmd->name, "MaxClients")) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(00521)
"MaxClients is deprecated, use MaxRequestWorkers "
"instead.");
}
max_workers = atoi(arg);
return NULL;
}
static const char *set_threads_per_child(cmd_parms * cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
threads_per_child = atoi(arg);
return NULL;
}
static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
server_limit = atoi(arg);
return NULL;
}
static const char *set_thread_limit(cmd_parms * cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
thread_limit = atoi(arg);
return NULL;
}
static const char *set_worker_factor(cmd_parms * cmd, void *dummy,
const char *arg)
{
double val;
char *endptr;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
val = strtod(arg, &endptr);
if (*endptr)
return "error parsing value";
if (val <= 0)
return "AsyncRequestWorkerFactor argument must be a positive number";
worker_factor = val * WORKER_FACTOR_SCALE;
if (worker_factor == 0)
worker_factor = 1;
return NULL;
}
static const command_rec event_cmds[] = {
LISTEN_COMMANDS,
AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
"Number of child processes launched at server startup"),
AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
"Maximum number of child processes for this run of Apache"),
AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
"Minimum number of idle threads, to handle request spikes"),
AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
"Maximum number of idle threads"),
AP_INIT_TAKE1("MaxClients", set_max_workers, NULL, RSRC_CONF,
"Deprecated name of MaxRequestWorkers"),
AP_INIT_TAKE1("MaxRequestWorkers", set_max_workers, NULL, RSRC_CONF,
"Maximum number of threads alive at the same time"),
AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
"Number of threads each child creates"),
AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
"Maximum number of worker threads per child process for this "
"run of Apache - Upper limit for ThreadsPerChild"),
AP_INIT_TAKE1("AsyncRequestWorkerFactor", set_worker_factor, NULL, RSRC_CONF,
"How many additional connects will be accepted per idle "
"worker thread"),
AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
{NULL}
};
AP_DECLARE_MODULE(mpm_eventopt) = {
MPM20_MODULE_STUFF,
NULL, /* hook to run before apache parses args */
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
event_cmds, /* command apr_table_t */
event_hooks /* register_hooks */
};