event.c revision 219c1ab259be52daf74b530ee9f80e02c723b7a8
2d2eda71267231c2526be701fe655db125852c1ffielding/* Licensed to the Apache Software Foundation (ASF) under one or more
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * contributor license agreements. See the NOTICE file distributed with
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * this work for additional information regarding copyright ownership.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * The ASF licenses this file to You under the Apache License, Version 2.0
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * (the "License"); you may not use this file except in compliance with
2d2eda71267231c2526be701fe655db125852c1ffielding * the License. You may obtain a copy of the License at
2d2eda71267231c2526be701fe655db125852c1ffielding * Unless required by applicable law or agreed to in writing, software
2d2eda71267231c2526be701fe655db125852c1ffielding * distributed under the License is distributed on an "AS IS" BASIS,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2d2eda71267231c2526be701fe655db125852c1ffielding * See the License for the specific language governing permissions and
2d2eda71267231c2526be701fe655db125852c1ffielding * limitations under the License.
2d2eda71267231c2526be701fe655db125852c1ffielding * This MPM tries to fix the 'keep alive problem' in HTTP.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * After a client completes the first request, the client can keep the
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * connection open to send more requests with the same socket. This can save
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * signifigant overhead in creating TCP connections. However, the major
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * disadvantage is that Apache traditionally keeps an entire child
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * process/thread waiting for data from the client. To solve this problem,
2d2eda71267231c2526be701fe655db125852c1ffielding * this MPM has a dedicated thread for handling both the Listenting sockets,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * and all sockets that are in a Keep Alive status.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * The MPM assumes the underlying apr_pollset implementation is somewhat
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * threadsafe. This currently is only compatible with KQueue and EPoll. This
2d2eda71267231c2526be701fe655db125852c1ffielding * enables the MPM to avoid extra high level locking or having to wake up the
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * listener thread when a keep-alive socket needs to be sent to it.
64185f9824e42f21ca7b9ae6c004484215c031a7rbb * This MPM not preform well on older platforms that do not have very good
2d2eda71267231c2526be701fe655db125852c1ffielding * threading, like Linux with a 2.4 kernel, but this does not matter, since we
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * require EPoll or KQueue.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * For FreeBSD, use 5.3. It is possible to run this MPM on FreeBSD 5.2.1, if
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * you use libkse (see `man libmap.conf`).
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * For NetBSD, use at least 2.0.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * For Linux, you should use a 2.6 kernel, and make sure your glibc has epoll
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * support compiled in.
952908500d5f99f35afc5ed510391b9bdc3833farbb#error The Event MPM requires APR threads, but they are unavailable.
2d2eda71267231c2526be701fe655db125852c1ffielding/* Limit on the total --- clients will be locked out if more servers than
2d2eda71267231c2526be701fe655db125852c1ffielding * this are needed. It is intended solely to keep the server from crashing
2e123e8beedc9f921448c113e2d6823a92fd5261fielding * when things get out of hand.
2d2eda71267231c2526be701fe655db125852c1ffielding * We keep a hard maximum number of servers, for two reasons --- first off,
2d2eda71267231c2526be701fe655db125852c1ffielding * in case something goes seriously wrong, we want to stop the fork bomb
2d2eda71267231c2526be701fe655db125852c1ffielding * short of actually crashing the machine we're running on by filling some
2d2eda71267231c2526be701fe655db125852c1ffielding * kernel table. Secondly, it keeps the size of the scoreboard file small
2d2eda71267231c2526be701fe655db125852c1ffielding * enough that we can read the whole thing without worrying too much about
2d2eda71267231c2526be701fe655db125852c1ffielding * the overhead.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * some sort of compile-time limit to help catch typos.
2d2eda71267231c2526be701fe655db125852c1ffielding/* Limit on the threads per process. Clients will be locked out if more than
2d2eda71267231c2526be701fe655db125852c1ffielding * this are needed.
2d2eda71267231c2526be701fe655db125852c1ffielding * We keep this for one reason it keeps the size of the scoreboard file small
2d2eda71267231c2526be701fe655db125852c1ffielding * enough that we can read the whole thing without worrying too much about
2d2eda71267231c2526be701fe655db125852c1ffielding * the overhead.
2d2eda71267231c2526be701fe655db125852c1ffielding/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
2d2eda71267231c2526be701fe655db125852c1ffielding * some sort of compile-time limit to help catch typos.
2d2eda71267231c2526be701fe655db125852c1ffielding#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
2d2eda71267231c2526be701fe655db125852c1ffielding * Actual definitions of config globals
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int threads_per_child = 0; /* Worker threads per child */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int ap_daemons_limit = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int max_clients = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int server_limit = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int thread_limit = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int dying = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int workers_may_exit = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int num_listensocks = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic struct timeout_head_t timeout_head, keepalive_timeout_head;
2d2eda71267231c2526be701fe655db125852c1ffieldingtypedef struct {
2d2eda71267231c2526be701fe655db125852c1ffielding/* The structure used to pass unique initialization info to each thread */
2d2eda71267231c2526be701fe655db125852c1ffieldingtypedef struct
2d2eda71267231c2526be701fe655db125852c1ffielding/* Structure used to pass information to the thread responsible for
2d2eda71267231c2526be701fe655db125852c1ffielding * creating the rest of the threads.
2d2eda71267231c2526be701fe655db125852c1ffieldingtypedef struct
2d2eda71267231c2526be701fe655db125852c1ffieldingtypedef enum
2d2eda71267231c2526be701fe655db125852c1ffieldingtypedef struct
2d2eda71267231c2526be701fe655db125852c1ffielding/* data retained by event across load/unload of the module
2d2eda71267231c2526be701fe655db125852c1ffielding * allocated on first call to pre-config hook; located on
2d2eda71267231c2526be701fe655db125852c1ffielding * subsequent calls to pre-config hook
2d2eda71267231c2526be701fe655db125852c1ffieldingtypedef struct event_retained_data {
2d2eda71267231c2526be701fe655db125852c1ffielding#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
2d2eda71267231c2526be701fe655db125852c1ffielding * The max child slot ever assigned, preserved across restarts. Necessary
2d2eda71267231c2526be701fe655db125852c1ffielding * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
2d2eda71267231c2526be701fe655db125852c1ffielding * use this value to optimize routines that have to scan the entire
2d2eda71267231c2526be701fe655db125852c1ffielding * scoreboard.
2d2eda71267231c2526be701fe655db125852c1ffielding/* The event MPM respects a couple of runtime flags that can aid
2d2eda71267231c2526be701fe655db125852c1ffielding * in debugging. Setting the -DNO_DETACH flag will prevent the root process
2d2eda71267231c2526be701fe655db125852c1ffielding * from detaching from its controlling terminal. Additionally, setting
2d2eda71267231c2526be701fe655db125852c1ffielding * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
2d2eda71267231c2526be701fe655db125852c1ffielding * child_main loop running in the process which originally started up.
2d2eda71267231c2526be701fe655db125852c1ffielding * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
2d2eda71267231c2526be701fe655db125852c1ffielding * early in standalone_main; just continue through. This is the server
2d2eda71267231c2526be701fe655db125852c1ffielding * trying to kill off any child processes which it might have lying
2d2eda71267231c2526be701fe655db125852c1ffielding * around --- Apache doesn't keep track of their pids, it just sends
2d2eda71267231c2526be701fe655db125852c1ffielding * SIGHUP to the process group, ignoring it in the root process.
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet * Continue through and you'll be fine.).
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudetstatic int one_process = 0;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic apr_pool_t *pconf; /* Pool for config stuff */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
2d2eda71267231c2526be701fe655db125852c1ffielding thread. Use this instead */
2d2eda71267231c2526be701fe655db125852c1ffielding/* The LISTENER_SIGNAL signal will be sent from the main thread to the
2d2eda71267231c2526be701fe655db125852c1ffielding * listener thread to wake it up for graceful termination (what a child
2d2eda71267231c2526be701fe655db125852c1ffielding * process from an old generation does when the admin does "apachectl
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * graceful"). This signal will be blocked in all threads of a child
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * process except for the listener thread.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb/* An array of socket descriptors in use by each thread used to
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe * perform a non-graceful (forced) shutdown of the server.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbstatic void close_worker_sockets(void)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb for (i = 0; i < threads_per_child; i++) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbstatic void wakeup_listener(void)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* XXX there is an obscure path that this doesn't handle perfectly:
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * right after listener thread is created but before
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * listener_os_thread is set, the first worker thread hits an
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * error and starts graceful termination
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* unblock the listener if it's waiting for a worker */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * platforms and wake up the listener thread since it is the only thread
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * with SIGHUP unblocked, but that doesn't work on Linux
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* in case we weren't called from the listener thread, wake up the
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * listener thread
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* for ungraceful termination, let the workers exit now;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * for graceful termination, the listener thread will notify the
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * workers to exit once it has stopped accepting new connections
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb close_worker_sockets(); /* forcefully kill all current connections */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbstatic int event_query(int query_code, int *result, apr_status_t *rv)
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic apr_status_t event_note_child_killed(int childnum)
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic const char *event_get_name(void)
2d2eda71267231c2526be701fe655db125852c1ffielding return "event";
2d2eda71267231c2526be701fe655db125852c1ffielding/* a clean exit from a child with proper cleanup */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic void clean_child_exit(int code) __attribute__ ((noreturn));
2d2eda71267231c2526be701fe655db125852c1ffielding/*****************************************************************
2d2eda71267231c2526be701fe655db125852c1ffielding * Connection structures and accounting...
2d2eda71267231c2526be701fe655db125852c1ffielding/* volatile just in case */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int volatile shutdown_pending;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int volatile restart_pending;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int volatile is_graceful;
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic volatile int child_fatal;
2d2eda71267231c2526be701fe655db125852c1ffielding * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
2d2eda71267231c2526be701fe655db125852c1ffielding * functions to initiate shutdown or restart without relying on signals.
2d2eda71267231c2526be701fe655db125852c1ffielding * Previously this was initiated in sig_term() and restart() signal handlers,
2d2eda71267231c2526be701fe655db125852c1ffielding * but we want to be able to start a shutdown/restart from other sources --
2d2eda71267231c2526be701fe655db125852c1ffielding * e.g. on Win32, from the service manager. Now the service manager can
2d2eda71267231c2526be701fe655db125852c1ffielding * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
2d2eda71267231c2526be701fe655db125852c1ffielding * these functions can also be called by the child processes, since global
2d2eda71267231c2526be701fe655db125852c1ffielding * variables are no longer used to pass on the required action to the parent.
2d2eda71267231c2526be701fe655db125852c1ffielding * These should only be called from the parent process itself, since the
2d2eda71267231c2526be701fe655db125852c1ffielding * parent process will use the shutdown_pending and restart_pending variables
2d2eda71267231c2526be701fe655db125852c1ffielding * to determine whether to shutdown or restart. The child process should
763f7b125b6d3dd1e4992a3822005efa2616f983coar * call signal_parent() directly to tell the parent to die -- this will
763f7b125b6d3dd1e4992a3822005efa2616f983coar * cause neither of those variable to be set, which the parent will
2d2eda71267231c2526be701fe655db125852c1ffielding * assume means something serious is wrong (which it will be, for the
2d2eda71267231c2526be701fe655db125852c1ffielding * child to force an exit) and so do an exit anyway.
2d2eda71267231c2526be701fe655db125852c1ffielding /* Um, is this _probably_ not an error, if the user has
2d2eda71267231c2526be701fe655db125852c1ffielding * tried to do a shutdown twice quickly, so we won't
2d2eda71267231c2526be701fe655db125852c1ffielding * worry about reporting it.
2d2eda71267231c2526be701fe655db125852c1ffielding/* do a graceful restart if graceful == 1 */
2d2eda71267231c2526be701fe655db125852c1ffielding /* Probably not an error - don't bother reporting it */
54e94821097724bf413d2d4cc70711760f7494e1trawickstatic void set_signals(void)
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding "sigaction(SIGTERM)");
2d2eda71267231c2526be701fe655db125852c1ffielding if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding "sigaction(SIGINT)");
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding "sigaction(SIGXCPU)");
952908500d5f99f35afc5ed510391b9bdc3833farbb ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
952908500d5f99f35afc5ed510391b9bdc3833farbb "sigaction(SIGXFSZ)");
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
3887202241db08986e94b252fbd06a55e55d4b2dbhyde "sigaction(SIGPIPE)");
3887202241db08986e94b252fbd06a55e55d4b2dbhyde /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
3887202241db08986e94b252fbd06a55e55d4b2dbhyde * processing one */
3887202241db08986e94b252fbd06a55e55d4b2dbhyde ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding "sigaction(SIGHUP)");
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
3a50e4da8a0db4515ab45678e5b39ff7e7594320trawick#endif /* SIGXCPU */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm#endif /* SIGXFSZ */
3a50e4da8a0db4515ab45678e5b39ff7e7594320trawick#endif /* SIGHUP */
3887202241db08986e94b252fbd06a55e55d4b2dbhyde#endif /* AP_SIG_GRACEFUL */
952908500d5f99f35afc5ed510391b9bdc3833farbb#endif /* AP_SIG_GRACEFUL_STOP */
3887202241db08986e94b252fbd06a55e55d4b2dbhyde#endif /* SIGPIPE */
3887202241db08986e94b252fbd06a55e55d4b2dbhyde/*****************************************************************
3887202241db08986e94b252fbd06a55e55d4b2dbhyde * Child process main loop.
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * sock,
2d2eda71267231c2526be701fe655db125852c1ffielding long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
952908500d5f99f35afc5ed510391b9bdc3833farbb ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
2d2eda71267231c2526be701fe655db125852c1ffielding c = ap_run_create_connection(p, ap_server_conf, sock,
952908500d5f99f35afc5ed510391b9bdc3833farbb ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
952908500d5f99f35afc5ed510391b9bdc3833farbb "process_socket: connection aborted");
2d2eda71267231c2526be701fe655db125852c1ffielding * XXX If the platform does not have a usable way of bundling
2d2eda71267231c2526be701fe655db125852c1ffielding * accept() with a socket readability check, like Win32,
2d2eda71267231c2526be701fe655db125852c1ffielding * and there are measurable delays before the
2d2eda71267231c2526be701fe655db125852c1ffielding * socket is readable due to the first data packet arriving,
2d2eda71267231c2526be701fe655db125852c1ffielding * it might be better to create the cs on the listener thread
952908500d5f99f35afc5ed510391b9bdc3833farbb * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE
952908500d5f99f35afc5ed510391b9bdc3833farbb * FreeBSD users will want to enable the HTTP accept filter
952908500d5f99f35afc5ed510391b9bdc3833farbb * module in their kernel for the highest performance
952908500d5f99f35afc5ed510391b9bdc3833farbb * When the accept filter is active, sockets are kept in the
952908500d5f99f35afc5ed510391b9bdc3833farbb * kernel until a HTTP request is received.
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Since we have an input filter which 'cloggs' the input stream,
952908500d5f99f35afc5ed510391b9bdc3833farbb * like mod_ssl, lets just do the normal read from input filters,
952908500d5f99f35afc5ed510391b9bdc3833farbb * like the Worker MPM does.
952908500d5f99f35afc5ed510391b9bdc3833farbb /* state will be updated upon return
2d2eda71267231c2526be701fe655db125852c1ffielding * fall thru to either wait for readability/timeout or
2d2eda71267231c2526be701fe655db125852c1ffielding * do lingering close
952908500d5f99f35afc5ed510391b9bdc3833farbb rv = output_filter->frec->filter_func.out_func(output_filter, NULL);
952908500d5f99f35afc5ed510391b9bdc3833farbb ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
952908500d5f99f35afc5ed510391b9bdc3833farbb "network write failure in core output filter");
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Still in WRITE_COMPLETION_STATE:
952908500d5f99f35afc5ed510391b9bdc3833farbb * Set a write timeout for this connection, and let the
2d2eda71267231c2526be701fe655db125852c1ffielding * event thread poll for writeability.
2d2eda71267231c2526be701fe655db125852c1ffielding cs->expiration_time = ap_server_conf->timeout + apr_time_now();
2d2eda71267231c2526be701fe655db125852c1ffielding APR_RING_INSERT_TAIL(&timeout_head, cs, conn_state_t, timeout_list);
2d2eda71267231c2526be701fe655db125852c1ffielding cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR;
2d2eda71267231c2526be701fe655db125852c1ffielding else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
952908500d5f99f35afc5ed510391b9bdc3833farbb else if (c->data_in_input_filters) {
2d2eda71267231c2526be701fe655db125852c1ffielding else if (cs->state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
2d2eda71267231c2526be701fe655db125852c1ffielding listener_poll_type *pt = (listener_poll_type *) cs->pfd.client_data;
952908500d5f99f35afc5ed510391b9bdc3833farbb /* It greatly simplifies the logic to use a single timeout value here
2d2eda71267231c2526be701fe655db125852c1ffielding * because the new element can just be added to the end of the list and
952908500d5f99f35afc5ed510391b9bdc3833farbb * it will stay sorted in expiration time sequence. If brand new
952908500d5f99f35afc5ed510391b9bdc3833farbb * sockets are sent to the event thread for a readability check, this
952908500d5f99f35afc5ed510391b9bdc3833farbb * will be a slight behavior change - they use the non-keepalive
952908500d5f99f35afc5ed510391b9bdc3833farbb * timeout today. With a normal client, the socket will be readable in
2d2eda71267231c2526be701fe655db125852c1ffielding * a few milliseconds anyway.
952908500d5f99f35afc5ed510391b9bdc3833farbb cs->expiration_time = ap_server_conf->keep_alive_timeout +
952908500d5f99f35afc5ed510391b9bdc3833farbb APR_RING_INSERT_TAIL(&keepalive_timeout_head, cs, conn_state_t, timeout_list);
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Add work to pollset. */
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding "process_socket: apr_pollset_add failure");
952908500d5f99f35afc5ed510391b9bdc3833farbb/* requests_this_child has gone to zero or below. See if the admin coded
2d2eda71267231c2526be701fe655db125852c1ffielding "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way
952908500d5f99f35afc5ed510391b9bdc3833farbb simplifies the hot path in worker_thread */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic void check_infinite_requests(void)
2d2eda71267231c2526be701fe655db125852c1ffielding /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
2d2eda71267231c2526be701fe655db125852c1ffielding * then we don't need this goofy function.
2d2eda71267231c2526be701fe655db125852c1ffielding /* XXXXX: recycle listener_poll_types */
952908500d5f99f35afc5ed510391b9bdc3833farbb APR_RING_INIT(&timeout_head, conn_state_t, timeout_list);
952908500d5f99f35afc5ed510391b9bdc3833farbb APR_RING_INIT(&keepalive_timeout_head, conn_state_t, timeout_list);
952908500d5f99f35afc5ed510391b9bdc3833farbb /* TODO: subpools, threads, reuse, etc. -- currently use malloc() inside :( */
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic apr_status_t push_timer2worker(timer_event_t* te)
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic apr_status_t push2worker(const apr_pollfd_t * pfd,
952908500d5f99f35afc5ed510391b9bdc3833farbb listener_poll_type *pt = (listener_poll_type *) pfd->client_data;
2d2eda71267231c2526be701fe655db125852c1ffielding * Some of the pollset backends, like KQueue or Epoll
952908500d5f99f35afc5ed510391b9bdc3833farbb * automagically remove the FD if the socket is closed,
3887202241db08986e94b252fbd06a55e55d4b2dbhyde * therefore, we can accept _SUCCESS or _NOTFOUND,
952908500d5f99f35afc5ed510391b9bdc3833farbb * and we still want to keep going
2d2eda71267231c2526be701fe655db125852c1ffielding if (rc != APR_SUCCESS && !APR_STATUS_IS_NOTFOUND(rc)) {
2d2eda71267231c2526be701fe655db125852c1ffielding rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p);
2d2eda71267231c2526be701fe655db125852c1ffielding /* trash the connection; we couldn't queue the connected
2d2eda71267231c2526be701fe655db125852c1ffielding * socket to a worker
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/* get_worker:
952908500d5f99f35afc5ed510391b9bdc3833farbb * reserve a worker thread, block if all are currently busy.
2d2eda71267231c2526be701fe655db125852c1ffielding * this prevents the worker queue from overflowing and lets
2d2eda71267231c2526be701fe655db125852c1ffielding * other processes accept new connections in the mean time.
169f62b04de69074b561b4e6dcf6f82572a5e367trawick rc = ap_queue_info_wait_for_idler(worker_queue_info);
952908500d5f99f35afc5ed510391b9bdc3833farbb "ap_queue_info_wait_for_idler failed. "
952908500d5f99f35afc5ed510391b9bdc3833farbb "Attempting to shutdown process gracefully");
952908500d5f99f35afc5ed510391b9bdc3833farbb /* already reserved a worker thread - must have hit a
952908500d5f99f35afc5ed510391b9bdc3833farbb * transient error on a previous pass
952908500d5f99f35afc5ed510391b9bdc3833farbb/* XXXXXX: Convert to skiplist or other better data structure
952908500d5f99f35afc5ed510391b9bdc3833farbb * (yes, this is VERY VERY VERY VERY BAD)
952908500d5f99f35afc5ed510391b9bdc3833farbb/* Structures to reuse */
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic APR_RING_HEAD(timer_free_ring_t, timer_event_t) timer_free_ring;
952908500d5f99f35afc5ed510391b9bdc3833farbb/* Active timers */
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic APR_RING_HEAD(timer_ring_t, timer_event_t) timer_ring;
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic apr_status_t event_register_timed_callback(apr_time_t t,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* oh yeah, and make locking smarter/fine grained. */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (!APR_RING_EMPTY(&timer_free_ring, timer_event_t, link)) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* XXXXX: lol, pool allocation without a context from any thread.Yeah. Right. MPMs Suck. */
e68becff3c3ddc18723c9799b8cc2e6e9c3dbd66wrowe /* XXXXX: optimize */
e68becff3c3ddc18723c9799b8cc2e6e9c3dbd66wrowe /* Okay, insert sorted by when.. */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb APR_RING_INSERT_TAIL(&timer_ring, te, timer_event_t, link);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbstatic void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy)
952908500d5f99f35afc5ed510391b9bdc3833farbb apr_pool_t *ptrans; /* Pool for per-transaction stuff */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* the following times out events that are really close in the future
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * to prevent extra poll calls
2d2eda71267231c2526be701fe655db125852c1ffielding * current value is .1 second
952908500d5f99f35afc5ed510391b9bdc3833farbb "failed to initialize pollset, "
952908500d5f99f35afc5ed510391b9bdc3833farbb "attempting to shutdown process gracefully");
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Unblock the signal used to wake this thread up, and set a handler for
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!APR_RING_EMPTY(&timer_ring, timer_event_t, link)) {
952908500d5f99f35afc5ed510391b9bdc3833farbb /* TOOD: what should do here? ugh. */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm rc = apr_pollset_poll(event_pollset, timeout_interval, &num,
952908500d5f99f35afc5ed510391b9bdc3833farbb "apr_pollset_poll failed. Attempting to "
952908500d5f99f35afc5ed510391b9bdc3833farbb "shutdown process gracefully");
952908500d5f99f35afc5ed510391b9bdc3833farbb /* one of the sockets is readable */
952908500d5f99f35afc5ed510391b9bdc3833farbb "event_loop: unexpected state %d",
952908500d5f99f35afc5ed510391b9bdc3833farbb /* A Listener Socket is ready for an accept() */
2d2eda71267231c2526be701fe655db125852c1ffielding /* create a new transaction pool for each accepted socket */
952908500d5f99f35afc5ed510391b9bdc3833farbb "Failed to create transaction pool");
952908500d5f99f35afc5ed510391b9bdc3833farbb /* later we trash rv and rely on csd to indicate
952908500d5f99f35afc5ed510391b9bdc3833farbb /* E[NM]FILE, ENOMEM, etc */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* trash the connection; we couldn't queue the connected
952908500d5f99f35afc5ed510391b9bdc3833farbb * socket to a worker
2d2eda71267231c2526be701fe655db125852c1ffielding "ap_queue_push failed");
952908500d5f99f35afc5ed510391b9bdc3833farbb } /* if:else on pt->type */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* send socket to serf. */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* XXXX: this doesn't require get_worker(&have_idle_worker) */
952908500d5f99f35afc5ed510391b9bdc3833farbb } /* while for processing poll */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* XXX possible optimization: stash the current time for use as
952908500d5f99f35afc5ed510391b9bdc3833farbb * r->request_time for new requests
952908500d5f99f35afc5ed510391b9bdc3833farbb /* handle timed out sockets */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Step 1: keepalive timeouts */
952908500d5f99f35afc5ed510391b9bdc3833farbb while (!APR_RING_EMPTY(&keepalive_timeout_head, conn_state_t, timeout_list)
952908500d5f99f35afc5ed510391b9bdc3833farbb /* XXX return NULL looks wrong - not an init failure
952908500d5f99f35afc5ed510391b9bdc3833farbb * that bypasses all the cleanup outside the main loop
952908500d5f99f35afc5ed510391b9bdc3833farbb * break seems more like it
952908500d5f99f35afc5ed510391b9bdc3833farbb * need to evaluate seriousness of push2worker failures
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Step 2: write completion timeouts */
952908500d5f99f35afc5ed510391b9bdc3833farbb while (!APR_RING_EMPTY(&timeout_head, conn_state_t, timeout_list)
952908500d5f99f35afc5ed510391b9bdc3833farbb } /* listener main loop */
2d2eda71267231c2526be701fe655db125852c1ffielding ap_scoreboard_image->parent[process_slot].quiescing = 1;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* wake up the main thread */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/* XXX For ungraceful termination/restart, we definitely don't want to
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * wait for active connections to finish but we may want to wait
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * for idle workers to get out of the queue code and release mutexes,
2d2eda71267231c2526be701fe655db125852c1ffielding * since those mutexes are cleaned up pretty soon and some systems
06924437019f9871bc4ee49748511130548b7d35rbb * may not react favorably (i.e., segfault) if operations are attempted
2d2eda71267231c2526be701fe655db125852c1ffielding * on cleaned-up mutexes.
ffba30a2a49b298bfa65151bdf61ce3e3d4636d1manojstatic void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy)
2d2eda71267231c2526be701fe655db125852c1ffielding apr_pool_t *ptrans; /* Pool for per-transaction stuff */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
2d2eda71267231c2526be701fe655db125852c1ffielding ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current();
2d2eda71267231c2526be701fe655db125852c1ffielding ap_scoreboard_image->servers[process_slot][thread_slot].generation = my_generation;
2d2eda71267231c2526be701fe655db125852c1ffielding ap_update_child_status_from_indexes(process_slot, thread_slot,
50486fceda867c0bb0223d9548c7c1c9b194259dfielding rv = ap_queue_info_set_idle(worker_queue_info, NULL);
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm "ap_queue_info_set_idle failed. Attempting to "
2d2eda71267231c2526be701fe655db125852c1ffielding "shutdown process gracefully.");
2d2eda71267231c2526be701fe655db125852c1ffielding ap_update_child_status_from_indexes(process_slot, thread_slot,
2d2eda71267231c2526be701fe655db125852c1ffielding rv = ap_queue_pop_something(worker_queue, &csd, &cs, &ptrans, &te);
2d2eda71267231c2526be701fe655db125852c1ffielding /* We get APR_EOF during a graceful shutdown once all the
2d2eda71267231c2526be701fe655db125852c1ffielding * connections accepted by this server process have been handled.
2d2eda71267231c2526be701fe655db125852c1ffielding /* We get APR_EINTR whenever ap_queue_pop() has been interrupted
2d2eda71267231c2526be701fe655db125852c1ffielding * from an explicit call to ap_queue_interrupt_all(). This allows
2d2eda71267231c2526be701fe655db125852c1ffielding * us to unblock threads stuck in ap_queue_pop() when a shutdown
2d2eda71267231c2526be701fe655db125852c1ffielding * is pending.
2d2eda71267231c2526be701fe655db125852c1ffielding * If workers_may_exit is set and this is ungraceful termination/
2d2eda71267231c2526be701fe655db125852c1ffielding * restart, we are bound to get an error on some systems (e.g.,
2d2eda71267231c2526be701fe655db125852c1ffielding * AIX, which sanity-checks mutex operations) since the queue
2d2eda71267231c2526be701fe655db125852c1ffielding * may have already been cleaned up. Don't log the "error" if
2d2eda71267231c2526be701fe655db125852c1ffielding * workers_may_exit is set.
2d2eda71267231c2526be701fe655db125852c1ffielding /* We got some other error. */
2d2eda71267231c2526be701fe655db125852c1ffielding ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
2d2eda71267231c2526be701fe655db125852c1ffielding "ap_queue_pop failed");
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben APR_RING_INSERT_TAIL(&timer_free_ring, te, timer_event_t, link);
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben rv = process_socket(thd, ptrans, csd, cs, process_slot, thread_slot);
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben ap_update_child_status_from_indexes(process_slot, thread_slot,
case SIGTERM:
case SIGINT:
int threads_created = 0;
int listener_started = 0;
int loops;
int prev_threads_created;
pchild);
* sizeof(apr_socket_t *));
for (i = 0; i < threads_per_child; i++) {
int status =
++loops;
return NULL;
if (listener) {
int iter;
iter = 0;
#ifdef HAVE_PTHREAD_KILL
++iter;
for (i = 0; i < threads_per_child; i++) {
if (ap_max_requests_per_child) {
sizeof(apr_thread_t *) *
if (ap_thread_stacksize != 0) {
if (one_process) {
switch (terminate_mode) {
case ST_GRACEFUL:
case ST_UNGRACEFUL:
int pid;
if (one_process) {
set_signals();
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
#ifndef MAX_SPAWN_RATE
static int hold_off_on_exponential_spawning;
static void perform_idle_server_maintenance(void)
int idle_thread_count;
int free_length;
int totally_free_length = 0;
int last_non_dead;
int total_non_dead;
int active_thread_count = 0;
free_length = 0;
idle_thread_count = 0;
total_non_dead = 0;
for (i = 0; i < ap_daemons_limit; ++i) {
int any_dying_threads = 0;
int any_dead_threads = 0;
if (i >= max_daemons_limit
for (j = 0; j < threads_per_child; j++) {
if (any_dead_threads
if (all_dead_threads) {
++free_length;
if (!any_dying_threads) {
last_non_dead = i;
if (sick_child_detected) {
if (active_thread_count > 0) {
sick_child_detected = 0;
static int reported = 0;
if (!reported) {
"or Min/MaxSpareThreads), "
for (i = 0; i < free_length; ++i) {
int child_slot;
if (child_slot >= 0) {
for (i = 0; i < threads_per_child; i++)
else if (remaining_children_to_start
status) == 0) {
else if (is_graceful) {
else if (remaining_children_to_start) {
if (!is_graceful) {
return DONE;
set_signals();
if (!is_graceful) {
if (!child_fatal) {
return DONE;
} else if (shutdown_pending) {
int active_children;
int index;
if (!child_fatal) {
if (ap_graceful_shutdown_timeout) {
shutdown_pending = 0;
active_children = 0;
return DONE;
if (one_process) {
return DONE;
if (is_graceful) {
/* wake up the children...time to die. But we'll have more soon */
return OK;
int startup = 0;
int level_flags = 0;
pconf = p;
return DONE;
if (!one_process) {
return DONE;
return OK;
if (debug) {
no_detach = 0;
if (!retained) {
is_graceful = 0;
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
ap_extended_status = 0;
return OK;
int startup = 0;
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (ap_daemons_to_start < 0) {
if (startup) {
if (startup) {
return OK;
one_process = 0;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
return err;
return NULL;
const char *arg)
return err;
return NULL;
{NULL}