1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * This MPM tries to fix the 'keep alive problem' in HTTP.
20 * After a client completes the first request, the client can keep the
21 * connection open to send more requests with the same socket. This can save
22 * significant overhead in creating TCP connections. However, the major
23 * disadvantage is that Apache traditionally keeps an entire child
24 * process/thread waiting for data from the client. To solve this problem,
25 * this MPM has a dedicated thread for handling both the Listening sockets,
26 * and all sockets that are in a Keep Alive status.
28 * The MPM assumes the underlying apr_pollset implementation is somewhat
29 * threadsafe. This currently is only compatible with KQueue and EPoll. This
30 * enables the MPM to avoid extra high level locking or having to wake up the
31 * listener thread when a keep-alive socket needs to be sent to it.
33 * This MPM does not perform well on older platforms that do not have very good
34 * threading, like Linux with a 2.4 kernel, but this does not matter, since we
35 * require EPoll or KQueue.
37 * For FreeBSD, use 5.3. It is possible to run this MPM on FreeBSD 5.2.1, if
38 * you use libkse (see `man libmap.conf`).
40 * For NetBSD, use at least 2.0.
42 * For Linux, you should use a 2.6 kernel, and make sure your glibc has epoll
43 * support compiled in.
48 #include "apr_portable.h"
49 #include "apr_strings.h"
50 #include "apr_file_io.h"
51 #include "apr_thread_proc.h"
52 #include "apr_signal.h"
53 #include "apr_thread_mutex.h"
56 #include "apr_queue.h"
57 #include "apr_atomic.h"
58 #define APR_WANT_STRFUNC
61 #include "apr_version.h"
68 #if APR_HAVE_SYS_SOCKET_H
69 #include <sys/socket.h>
71 #if APR_HAVE_SYS_WAIT_H
74 #ifdef HAVE_SYS_PROCESSOR_H
75 #include <sys/processor.h> /* for bindprocessor() */
79 #error The Event MPM requires APR threads, but they are unavailable.
82 #include "ap_config.h"
84 #include "http_main.h"
86 #include "http_config.h" /* for read_config */
87 #include "http_core.h" /* for get_remote_host */
88 #include "http_connection.h"
89 #include "http_protocol.h"
91 #include "mpm_common.h"
92 #include "ap_listen.h"
93 #include "scoreboard.h"
95 #include "mpm_default.h"
96 #include "http_vhost.h"
98 #include "apr_skiplist.h"
99 #include "util_time.h"
102 #include <limits.h> /* for INT_MAX */
106 #include "mod_serf.h"
110 /* Limit on the total --- clients will be locked out if more servers than
111 * this are needed. It is intended solely to keep the server from crashing
112 * when things get out of hand.
114 * We keep a hard maximum number of servers, for two reasons --- first off,
115 * in case something goes seriously wrong, we want to stop the fork bomb
116 * short of actually crashing the machine we're running on by filling some
117 * kernel table. Secondly, it keeps the size of the scoreboard file small
118 * enough that we can read the whole thing without worrying too much about
121 #ifndef DEFAULT_SERVER_LIMIT
122 #define DEFAULT_SERVER_LIMIT 16
125 /* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
126 * some sort of compile-time limit to help catch typos.
128 #ifndef MAX_SERVER_LIMIT
129 #define MAX_SERVER_LIMIT 20000
132 /* Limit on the threads per process. Clients will be locked out if more than
135 * We keep this for one reason it keeps the size of the scoreboard file small
136 * enough that we can read the whole thing without worrying too much about
139 #ifndef DEFAULT_THREAD_LIMIT
140 #define DEFAULT_THREAD_LIMIT 64
143 /* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
144 * some sort of compile-time limit to help catch typos.
146 #ifndef MAX_THREAD_LIMIT
147 #define MAX_THREAD_LIMIT 100000
150 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
152 #if !APR_VERSION_AT_LEAST(1,4,0)
153 #define apr_time_from_msec(x) (x * 1000)
156 #ifndef MAX_SECS_TO_LINGER
157 #define MAX_SECS_TO_LINGER 30
159 #define SECONDS_TO_LINGER 2
162 * Actual definitions of config globals
165 #ifndef DEFAULT_WORKER_FACTOR
166 #define DEFAULT_WORKER_FACTOR 2
168 #define WORKER_FACTOR_SCALE 16 /* scale factor to allow fractional values */
169 static unsigned int worker_factor = DEFAULT_WORKER_FACTOR * WORKER_FACTOR_SCALE;
171 static int threads_per_child = 0; /* Worker threads per child */
172 static int ap_daemons_to_start = 0;
173 static int min_spare_threads = 0;
174 static int max_spare_threads = 0;
175 static int ap_daemons_limit = 0;
176 static int max_workers = 0;
177 static int server_limit = 0;
178 static int thread_limit = 0;
179 static int had_healthy_child = 0;
180 static int dying = 0;
181 static int workers_may_exit = 0;
182 static int start_thread_may_exit = 0;
183 static int listener_may_exit = 0;
184 static int num_listensocks = 0;
185 static apr_int32_t conns_this_child; /* MaxConnectionsPerChild, only access
186 in listener thread */
187 static apr_uint32_t connection_count = 0; /* Number of open connections */
188 static apr_uint32_t lingering_count = 0; /* Number of connections in lingering close */
189 static apr_uint32_t suspended_count = 0; /* Number of suspended connections */
190 static apr_uint32_t clogged_count = 0; /* Number of threads processing ssl conns */
191 static int resource_shortage = 0;
192 static fd_queue_t *worker_queue;
193 static fd_queue_info_t *worker_queue_info;
194 static int mpm_state = AP_MPMQ_STARTING;
196 static apr_thread_mutex_t *timeout_mutex;
198 module AP_MODULE_DECLARE_DATA mpm_event_module;
200 struct event_conn_state_t {
201 /** APR_RING of expiration timeouts */
202 APR_RING_ENTRY(event_conn_state_t) timeout_list;
203 /** the expiration time of the next keepalive timeout */
204 apr_time_t expiration_time;
205 /** connection record this struct refers to */
207 /** request record (if any) this struct refers to */
209 /** is the current conn_rec suspended? (disassociated with
210 * a particular MPM thread; for suspend_/resume_connection
214 /** memory pool to allocate from */
216 /** bucket allocator */
217 apr_bucket_alloc_t *bucket_alloc;
218 /** poll file descriptor information */
220 /** public parts of the connection state */
223 APR_RING_HEAD(timeout_head_t, event_conn_state_t);
225 struct timeout_queue {
226 struct timeout_head_t head;
231 * Several timeout queues that use different timeouts, so that we always can
232 * simply append to the end.
233 * write_completion_q uses TimeOut
234 * keepalive_q uses KeepAliveTimeOut
235 * linger_q uses MAX_SECS_TO_LINGER
236 * short_linger_q uses SECONDS_TO_LINGER
238 static struct timeout_queue write_completion_q, keepalive_q, linger_q,
240 static apr_pollfd_t *listener_pollfd;
243 * Macros for accessing struct timeout_queue.
244 * For TO_QUEUE_APPEND and TO_QUEUE_REMOVE, timeout_mutex must be held.
246 #define TO_QUEUE_APPEND(q, el) \
248 APR_RING_INSERT_TAIL(&(q).head, el, event_conn_state_t, timeout_list); \
252 #define TO_QUEUE_REMOVE(q, el) \
254 APR_RING_REMOVE(el, timeout_list); \
258 #define TO_QUEUE_INIT(q) \
260 APR_RING_INIT(&(q).head, event_conn_state_t, timeout_list); \
264 #define TO_QUEUE_ELEM_INIT(el) APR_RING_ELEM_INIT(el, timeout_list)
267 * The pollset for sockets that are in any of the timeout queues. Currently
268 * we use the timeout_mutex to make sure that connections are added/removed
269 * atomically to/from both event_pollset and a timeout queue. Otherwise
270 * some confusion can happen under high load if timeout queues and pollset
272 * XXX: It should be possible to make the lock unnecessary in many or even all
275 static apr_pollset_t *event_pollset;
279 apr_pollset_t *pollset;
283 static serf_context_t *g_serf;
286 /* The structure used to pass unique initialization info to each thread */
294 /* Structure used to pass information to the thread responsible for
295 * creating the rest of the threads.
299 apr_thread_t **threads;
300 apr_thread_t *listener;
302 apr_threadattr_t *threadattr;
319 } listener_poll_type;
323 ap_mpm_socket_callback_fn_t *cbfunc;
327 timer_event_t *cancel_event; /* If a timeout was requested, a pointer to the timer event */
328 unsigned int signaled:1;
329 } socket_callback_baton_t;
331 /* data retained by event across load/unload of the module
332 * allocated on first call to pre-config hook; located on
333 * subsequent calls to pre-config hook
335 typedef struct event_retained_data {
336 int first_server_limit;
337 int first_thread_limit;
339 int sick_child_detected;
340 ap_generation_t my_generation;
341 int volatile is_graceful; /* set from signal handler */
342 int maxclients_reported;
344 * The max child slot ever assigned, preserved across restarts. Necessary
345 * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts.
346 * We use this value to optimize routines that have to scan the entire
349 int max_daemons_limit;
351 * idle_spawn_rate is the number of children that will be spawned on the
352 * next maintenance cycle if there aren't enough idle servers. It is
353 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
354 * without the need to spawn.
356 int *idle_spawn_rate;
357 #ifndef MAX_SPAWN_RATE
358 #define MAX_SPAWN_RATE (32)
360 int hold_off_on_exponential_spawning;
361 } event_retained_data;
362 static event_retained_data *retained;
364 #define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
366 static ap_pod_t **pod;
367 static ap_pod_t *child_pod;
368 static ap_listen_rec *child_listen;
369 static int *bucket; /* bucket array for the httpd child processes */
371 /* The event MPM respects a couple of runtime flags that can aid
372 * in debugging. Setting the -DNO_DETACH flag will prevent the root process
373 * from detaching from its controlling terminal. Additionally, setting
374 * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
375 * child_main loop running in the process which originally started up.
376 * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
377 * early in standalone_main; just continue through. This is the server
378 * trying to kill off any child processes which it might have lying
379 * around --- Apache doesn't keep track of their pids, it just sends
380 * SIGHUP to the process group, ignoring it in the root process.
381 * Continue through and you'll be fine.).
384 static int one_process = 0;
387 int raise_sigstop_flags;
390 static apr_pool_t *pconf; /* Pool for config stuff */
391 static apr_pool_t *pchild; /* Pool for httpd child stuff */
393 static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
394 thread. Use this instead */
395 static pid_t parent_pid;
396 static apr_os_thread_t *listener_os_thread;
398 /* The LISTENER_SIGNAL signal will be sent from the main thread to the
399 * listener thread to wake it up for graceful termination (what a child
400 * process from an old generation does when the admin does "apachectl
401 * graceful"). This signal will be blocked in all threads of a child
402 * process except for the listener thread.
404 #define LISTENER_SIGNAL SIGHUP
406 /* An array of socket descriptors in use by each thread used to
407 * perform a non-graceful (forced) shutdown of the server.
409 static apr_socket_t **worker_sockets;
411 static void disable_listensocks(int process_slot)
414 for (i = 0; i < num_listensocks; i++) {
415 apr_pollset_remove(event_pollset, &listener_pollfd[i]);
417 ap_scoreboard_image->parent[process_slot].not_accepting = 1;
420 static void enable_listensocks(int process_slot)
423 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00457)
424 "Accepting new connections again: "
425 "%u active conns (%u lingering/%u clogged/%u suspended), "
427 apr_atomic_read32(&connection_count),
428 apr_atomic_read32(&lingering_count),
429 apr_atomic_read32(&clogged_count),
430 apr_atomic_read32(&suspended_count),
431 ap_queue_info_get_idlers(worker_queue_info));
432 for (i = 0; i < num_listensocks; i++)
433 apr_pollset_add(event_pollset, &listener_pollfd[i]);
435 * XXX: This is not yet optimal. If many workers suddenly become available,
436 * XXX: the parent may kill some processes off too soon.
438 ap_scoreboard_image->parent[process_slot].not_accepting = 0;
441 static void close_worker_sockets(void)
444 for (i = 0; i < threads_per_child; i++) {
445 if (worker_sockets[i]) {
446 apr_socket_close(worker_sockets[i]);
447 worker_sockets[i] = NULL;
452 static void wakeup_listener(void)
454 listener_may_exit = 1;
455 if (!listener_os_thread) {
456 /* XXX there is an obscure path that this doesn't handle perfectly:
457 * right after listener thread is created but before
458 * listener_os_thread is set, the first worker thread hits an
459 * error and starts graceful termination
464 /* unblock the listener if it's waiting for a worker */
465 ap_queue_info_term(worker_queue_info);
468 * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
469 * platforms and wake up the listener thread since it is the only thread
470 * with SIGHUP unblocked, but that doesn't work on Linux
472 #ifdef HAVE_PTHREAD_KILL
473 pthread_kill(*listener_os_thread, LISTENER_SIGNAL);
475 kill(ap_my_pid, LISTENER_SIGNAL);
480 #define ST_GRACEFUL 1
481 #define ST_UNGRACEFUL 2
483 static int terminate_mode = ST_INIT;
485 static void signal_threads(int mode)
487 if (terminate_mode == mode) {
490 terminate_mode = mode;
491 mpm_state = AP_MPMQ_STOPPING;
493 /* in case we weren't called from the listener thread, wake up the
498 /* for ungraceful termination, let the workers exit now;
499 * for graceful termination, the listener thread will notify the
500 * workers to exit once it has stopped accepting new connections
502 if (mode == ST_UNGRACEFUL) {
503 workers_may_exit = 1;
504 ap_queue_interrupt_all(worker_queue);
505 close_worker_sockets(); /* forcefully kill all current connections */
509 static int event_query(int query_code, int *result, apr_status_t *rv)
512 switch (query_code) {
513 case AP_MPMQ_MAX_DAEMON_USED:
514 *result = retained->max_daemons_limit;
516 case AP_MPMQ_IS_THREADED:
517 *result = AP_MPMQ_STATIC;
519 case AP_MPMQ_IS_FORKED:
520 *result = AP_MPMQ_DYNAMIC;
522 case AP_MPMQ_IS_ASYNC:
525 case AP_MPMQ_HAS_SERF:
528 case AP_MPMQ_HARD_LIMIT_DAEMONS:
529 *result = server_limit;
531 case AP_MPMQ_HARD_LIMIT_THREADS:
532 *result = thread_limit;
534 case AP_MPMQ_MAX_THREADS:
535 *result = threads_per_child;
537 case AP_MPMQ_MIN_SPARE_DAEMONS:
540 case AP_MPMQ_MIN_SPARE_THREADS:
541 *result = min_spare_threads;
543 case AP_MPMQ_MAX_SPARE_DAEMONS:
546 case AP_MPMQ_MAX_SPARE_THREADS:
547 *result = max_spare_threads;
549 case AP_MPMQ_MAX_REQUESTS_DAEMON:
550 *result = ap_max_requests_per_child;
552 case AP_MPMQ_MAX_DAEMONS:
553 *result = ap_daemons_limit;
555 case AP_MPMQ_MPM_STATE:
558 case AP_MPMQ_GENERATION:
559 *result = retained->my_generation;
561 case AP_MPMQ_CAN_SUSPEND:
571 static void event_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
573 if (childnum != -1) { /* child had a scoreboard slot? */
574 ap_run_child_status(ap_server_conf,
575 ap_scoreboard_image->parent[childnum].pid,
576 ap_scoreboard_image->parent[childnum].generation,
577 childnum, MPM_CHILD_EXITED);
578 ap_scoreboard_image->parent[childnum].pid = 0;
581 ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
585 static void event_note_child_started(int slot, pid_t pid)
587 ap_scoreboard_image->parent[slot].pid = pid;
588 ap_run_child_status(ap_server_conf,
589 ap_scoreboard_image->parent[slot].pid,
590 retained->my_generation, slot, MPM_CHILD_STARTED);
593 static void event_note_child_lost_slot(int slot, pid_t newpid)
595 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00458)
596 "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
597 "%" APR_PID_T_FMT "%s",
599 ap_scoreboard_image->parent[slot].pid,
600 ap_scoreboard_image->parent[slot].quiescing ?
601 " (quiescing)" : "");
602 ap_run_child_status(ap_server_conf,
603 ap_scoreboard_image->parent[slot].pid,
604 ap_scoreboard_image->parent[slot].generation,
605 slot, MPM_CHILD_LOST_SLOT);
606 /* Don't forget about this exiting child process, or we
607 * won't be able to kill it if it doesn't exit by the
608 * time the server is shut down.
610 ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
611 ap_scoreboard_image->parent[slot].generation);
614 static const char *event_get_name(void)
619 /* a clean exit from a child with proper cleanup */
620 static void clean_child_exit(int code) __attribute__ ((noreturn));
621 static void clean_child_exit(int code)
623 mpm_state = AP_MPMQ_STOPPING;
625 apr_pool_destroy(pchild);
629 event_note_child_killed(/* slot */ 0, 0, 0);
635 static void just_die(int sig)
640 /*****************************************************************
641 * Connection structures and accounting...
644 static int child_fatal;
646 /* volatile because they're updated from a signal handler */
647 static int volatile shutdown_pending;
648 static int volatile restart_pending;
650 static apr_status_t decrement_connection_count(void *cs_)
652 event_conn_state_t *cs = cs_;
653 switch (cs->pub.state) {
654 case CONN_STATE_LINGER_NORMAL:
655 case CONN_STATE_LINGER_SHORT:
656 apr_atomic_dec32(&lingering_count);
658 case CONN_STATE_SUSPENDED:
659 apr_atomic_dec32(&suspended_count);
664 apr_atomic_dec32(&connection_count);
669 * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
670 * functions to initiate shutdown or restart without relying on signals.
671 * Previously this was initiated in sig_term() and restart() signal handlers,
672 * but we want to be able to start a shutdown/restart from other sources --
673 * e.g. on Win32, from the service manager. Now the service manager can
674 * call ap_start_shutdown() or ap_start_restart() as appropriate. Note that
675 * these functions can also be called by the child processes, since global
676 * variables are no longer used to pass on the required action to the parent.
678 * These should only be called from the parent process itself, since the
679 * parent process will use the shutdown_pending and restart_pending variables
680 * to determine whether to shutdown or restart. The child process should
681 * call signal_parent() directly to tell the parent to die -- this will
682 * cause neither of those variable to be set, which the parent will
683 * assume means something serious is wrong (which it will be, for the
684 * child to force an exit) and so do an exit anyway.
687 static void ap_start_shutdown(int graceful)
689 mpm_state = AP_MPMQ_STOPPING;
690 if (shutdown_pending == 1) {
691 /* Um, is this _probably_ not an error, if the user has
692 * tried to do a shutdown twice quickly, so we won't
693 * worry about reporting it.
697 shutdown_pending = 1;
698 retained->is_graceful = graceful;
701 /* do a graceful restart if graceful == 1 */
702 static void ap_start_restart(int graceful)
704 mpm_state = AP_MPMQ_STOPPING;
705 if (restart_pending == 1) {
706 /* Probably not an error - don't bother reporting it */
710 retained->is_graceful = graceful;
713 static void sig_term(int sig)
715 ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
718 static void restart(int sig)
720 ap_start_restart(sig == AP_SIG_GRACEFUL);
723 static void set_signals(void)
725 #ifndef NO_USE_SIGACTION
730 ap_fatal_signal_setup(ap_server_conf, pconf);
733 #ifndef NO_USE_SIGACTION
734 sigemptyset(&sa.sa_mask);
737 sa.sa_handler = sig_term;
738 if (sigaction(SIGTERM, &sa, NULL) < 0)
739 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00459)
740 "sigaction(SIGTERM)");
741 #ifdef AP_SIG_GRACEFUL_STOP
742 if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
743 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00460)
744 "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
747 if (sigaction(SIGINT, &sa, NULL) < 0)
748 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00461)
749 "sigaction(SIGINT)");
752 sa.sa_handler = SIG_DFL;
753 if (sigaction(SIGXCPU, &sa, NULL) < 0)
754 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00462)
755 "sigaction(SIGXCPU)");
758 /* For systems following the LFS standard, ignoring SIGXFSZ allows
759 * a write() beyond the 2GB limit to fail gracefully with E2BIG
760 * rather than terminate the process. */
761 sa.sa_handler = SIG_IGN;
762 if (sigaction(SIGXFSZ, &sa, NULL) < 0)
763 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00463)
764 "sigaction(SIGXFSZ)");
767 sa.sa_handler = SIG_IGN;
768 if (sigaction(SIGPIPE, &sa, NULL) < 0)
769 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00464)
770 "sigaction(SIGPIPE)");
773 /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
775 sigaddset(&sa.sa_mask, SIGHUP);
776 sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
777 sa.sa_handler = restart;
778 if (sigaction(SIGHUP, &sa, NULL) < 0)
779 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00465)
780 "sigaction(SIGHUP)");
781 if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
782 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00466)
783 "sigaction(" AP_SIG_GRACEFUL_STRING ")");
787 apr_signal(SIGXCPU, SIG_DFL);
790 apr_signal(SIGXFSZ, SIG_IGN);
794 apr_signal(SIGTERM, sig_term);
796 apr_signal(SIGHUP, restart);
798 #ifdef AP_SIG_GRACEFUL
799 apr_signal(AP_SIG_GRACEFUL, restart);
800 #endif /* AP_SIG_GRACEFUL */
801 #ifdef AP_SIG_GRACEFUL_STOP
802 apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
803 #endif /* AP_SIG_GRACEFUL_STOP */
805 apr_signal(SIGPIPE, SIG_IGN);
811 static int start_lingering_close_common(event_conn_state_t *cs)
814 struct timeout_queue *q;
815 apr_socket_t *csd = cs->pfd.desc.s;
818 rv = apr_socket_timeout_set(csd, 0);
819 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
822 apr_socket_timeout_set(csd, 0);
825 * If some module requested a shortened waiting period, only wait for
826 * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain
829 if (apr_table_get(cs->c->notes, "short-lingering-close")) {
830 cs->expiration_time =
831 apr_time_now() + apr_time_from_sec(SECONDS_TO_LINGER);
833 cs->pub.state = CONN_STATE_LINGER_SHORT;
836 cs->expiration_time =
837 apr_time_now() + apr_time_from_sec(MAX_SECS_TO_LINGER);
839 cs->pub.state = CONN_STATE_LINGER_NORMAL;
841 apr_atomic_inc32(&lingering_count);
842 apr_thread_mutex_lock(timeout_mutex);
843 TO_QUEUE_APPEND(*q, cs);
844 cs->pfd.reqevents = (
845 cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT :
846 APR_POLLIN) | APR_POLLHUP | APR_POLLERR;
847 cs->pub.sense = CONN_SENSE_DEFAULT;
848 rv = apr_pollset_add(event_pollset, &cs->pfd);
849 apr_thread_mutex_unlock(timeout_mutex);
850 if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) {
851 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
852 "start_lingering_close: apr_pollset_add failure");
853 apr_thread_mutex_lock(timeout_mutex);
854 TO_QUEUE_REMOVE(*q, cs);
855 apr_thread_mutex_unlock(timeout_mutex);
856 apr_socket_close(cs->pfd.desc.s);
857 apr_pool_clear(cs->p);
858 ap_push_pool(worker_queue_info, cs->p);
865 * Close our side of the connection, flushing data to the client first.
866 * Pre-condition: cs is not in any timeout queue and not in the pollset,
867 * timeout_mutex is not locked
868 * return: 0 if connection is fully closed,
869 * 1 if connection is lingering
870 * May only be called by worker thread.
872 static int start_lingering_close_blocking(event_conn_state_t *cs)
874 if (ap_start_lingering_close(cs->c)) {
875 apr_pool_clear(cs->p);
876 ap_push_pool(worker_queue_info, cs->p);
879 return start_lingering_close_common(cs);
883 * Close our side of the connection, NOT flushing data to the client.
884 * This should only be called if there has been an error or if we know
885 * that our send buffers are empty.
886 * Pre-condition: cs is not in any timeout queue and not in the pollset,
887 * timeout_mutex is not locked
888 * return: 0 if connection is fully closed,
889 * 1 if connection is lingering
890 * may be called by listener thread
892 static int start_lingering_close_nonblocking(event_conn_state_t *cs)
895 apr_socket_t *csd = cs->pfd.desc.s;
898 || ap_shutdown_conn(c, 0) != APR_SUCCESS || c->aborted
899 || apr_socket_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS) {
900 apr_socket_close(csd);
901 apr_pool_clear(cs->p);
902 ap_push_pool(worker_queue_info, cs->p);
905 return start_lingering_close_common(cs);
909 * forcibly close a lingering connection after the lingering period has
911 * Pre-condition: cs is not in any timeout queue and not in the pollset
912 * return: irrelevant (need same prototype as start_lingering_close)
914 static int stop_lingering_close(event_conn_state_t *cs)
917 apr_socket_t *csd = ap_get_conn_socket(cs->c);
918 ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
919 "socket reached timeout in lingering-close state");
920 rv = apr_socket_close(csd);
921 if (rv != APR_SUCCESS) {
922 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(00468) "error closing socket");
925 apr_pool_clear(cs->p);
926 ap_push_pool(worker_queue_info, cs->p);
930 static void notify_suspend(event_conn_state_t *cs)
932 ap_run_suspend_connection(cs->c, cs->r);
936 static void notify_resume(event_conn_state_t *cs)
939 ap_run_resume_connection(cs->c, cs->r);
943 * This runs before any non-MPM cleanup code on the connection;
944 * if the connection is currently suspended as far as modules
945 * know, provide notification of resumption.
947 static apr_status_t ptrans_pre_cleanup(void *dummy)
949 event_conn_state_t *cs = dummy;
958 * event_pre_read_request() and event_request_cleanup() track the
959 * current r for a given connection.
961 static apr_status_t event_request_cleanup(void *dummy)
964 event_conn_state_t *cs = ap_get_module_config(c->conn_config,
971 static void event_pre_read_request(request_rec *r, conn_rec *c)
973 event_conn_state_t *cs = ap_get_module_config(c->conn_config,
977 apr_pool_cleanup_register(r->pool, c, event_request_cleanup,
978 apr_pool_cleanup_null);
982 * process one connection in the worker
984 static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * sock,
985 event_conn_state_t * cs, int my_child_num,
989 long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
993 /* XXX: This will cause unbounded mem usage for long lasting connections */
994 ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
996 if (cs == NULL) { /* This is a new connection */
997 listener_poll_type *pt = apr_pcalloc(p, sizeof(*pt));
998 cs = apr_pcalloc(p, sizeof(event_conn_state_t));
999 cs->bucket_alloc = apr_bucket_alloc_create(p);
1000 c = ap_run_create_connection(p, ap_server_conf, sock,
1001 conn_id, sbh, cs->bucket_alloc);
1003 apr_bucket_alloc_destroy(cs->bucket_alloc);
1005 ap_push_pool(worker_queue_info, p);
1008 apr_atomic_inc32(&connection_count);
1009 apr_pool_cleanup_register(c->pool, cs, decrement_connection_count,
1010 apr_pool_cleanup_null);
1011 ap_set_module_config(c->conn_config, &mpm_event_module, cs);
1012 c->current_thread = thd;
1016 cs->pfd.desc_type = APR_POLL_SOCKET;
1017 cs->pfd.reqevents = APR_POLLIN;
1018 cs->pfd.desc.s = sock;
1021 cs->pfd.client_data = pt;
1022 apr_pool_pre_cleanup_register(p, cs, ptrans_pre_cleanup);
1023 TO_QUEUE_ELEM_INIT(cs);
1025 ap_update_vhost_given_ip(c);
1027 rc = ap_run_pre_connection(c, sock);
1028 if (rc != OK && rc != DONE) {
1029 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(00469)
1030 "process_socket: connection aborted");
1035 * XXX If the platform does not have a usable way of bundling
1036 * accept() with a socket readability check, like Win32,
1037 * and there are measurable delays before the
1038 * socket is readable due to the first data packet arriving,
1039 * it might be better to create the cs on the listener thread
1040 * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE
1042 * FreeBSD users will want to enable the HTTP accept filter
1043 * module in their kernel for the highest performance
1044 * When the accept filter is active, sockets are kept in the
1045 * kernel until a HTTP request is received.
1047 cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
1049 cs->pub.sense = CONN_SENSE_DEFAULT;
1055 c->current_thread = thd;
1058 if (c->clogging_input_filters && !c->aborted) {
1059 /* Since we have an input filter which 'clogs' the input stream,
1060 * like mod_ssl used to, lets just do the normal read from input
1061 * filters, like the Worker MPM does. Filters that need to write
1062 * where they would otherwise read, or read where they would
1063 * otherwise write, should set the sense appropriately.
1065 apr_atomic_inc32(&clogged_count);
1066 ap_run_process_connection(c);
1067 if (cs->pub.state != CONN_STATE_SUSPENDED) {
1068 cs->pub.state = CONN_STATE_LINGER;
1070 apr_atomic_dec32(&clogged_count);
1074 if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) {
1076 ap_run_process_connection(c);
1078 /* state will be updated upon return
1079 * fall thru to either wait for readability/timeout or
1080 * do lingering close
1084 cs->pub.state = CONN_STATE_LINGER;
1088 if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
1089 ap_filter_t *output_filter = c->output_filters;
1091 ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
1092 while (output_filter->next != NULL) {
1093 output_filter = output_filter->next;
1095 rv = output_filter->frec->filter_func.out_func(output_filter, NULL);
1096 if (rv != APR_SUCCESS) {
1097 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470)
1098 "network write failure in core output filter");
1099 cs->pub.state = CONN_STATE_LINGER;
1101 else if (c->data_in_output_filters) {
1102 /* Still in WRITE_COMPLETION_STATE:
1103 * Set a write timeout for this connection, and let the
1104 * event thread poll for writeability.
1106 cs->expiration_time = ap_server_conf->timeout + apr_time_now();
1109 apr_thread_mutex_lock(timeout_mutex);
1110 TO_QUEUE_APPEND(write_completion_q, cs);
1111 cs->pfd.reqevents = (
1112 cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN :
1113 APR_POLLOUT) | APR_POLLHUP | APR_POLLERR;
1114 cs->pub.sense = CONN_SENSE_DEFAULT;
1115 rc = apr_pollset_add(event_pollset, &cs->pfd);
1116 apr_thread_mutex_unlock(timeout_mutex);
1119 else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
1120 listener_may_exit) {
1121 cs->pub.state = CONN_STATE_LINGER;
1123 else if (c->data_in_input_filters) {
1124 cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
1128 cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
1132 if (cs->pub.state == CONN_STATE_LINGER) {
1133 if (!start_lingering_close_blocking(cs)) {
1139 else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
1140 /* It greatly simplifies the logic to use a single timeout value here
1141 * because the new element can just be added to the end of the list and
1142 * it will stay sorted in expiration time sequence. If brand new
1143 * sockets are sent to the event thread for a readability check, this
1144 * will be a slight behavior change - they use the non-keepalive
1145 * timeout today. With a normal client, the socket will be readable in
1146 * a few milliseconds anyway.
1148 cs->expiration_time = ap_server_conf->keep_alive_timeout +
1152 apr_thread_mutex_lock(timeout_mutex);
1153 TO_QUEUE_APPEND(keepalive_q, cs);
1155 /* Add work to pollset. */
1156 cs->pfd.reqevents = APR_POLLIN;
1157 rc = apr_pollset_add(event_pollset, &cs->pfd);
1158 apr_thread_mutex_unlock(timeout_mutex);
1160 if (rc != APR_SUCCESS) {
1161 ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
1162 "process_socket: apr_pollset_add failure");
1163 AP_DEBUG_ASSERT(rc == APR_SUCCESS);
1167 else if (cs->pub.state == CONN_STATE_SUSPENDED) {
1168 cs->c->suspended_baton = cs;
1169 apr_atomic_inc32(&suspended_count);
1172 * Prevent this connection from writing to our connection state after it
1173 * is no longer associated with this thread. This would happen if the EOR
1174 * bucket is destroyed from the listener thread due to a connection abort
1182 /* Put a SUSPENDED connection back into a queue. */
1183 static apr_status_t event_resume_suspended (conn_rec *c) {
1184 event_conn_state_t* cs = (event_conn_state_t*) c->suspended_baton;
1186 ap_log_cerror (APLOG_MARK, LOG_WARNING, 0, c, APLOGNO(02615)
1187 "event_resume_suspended: suspended_baton is NULL");
1188 return APR_EGENERAL;
1189 } else if (!cs->suspended) {
1190 ap_log_cerror (APLOG_MARK, LOG_WARNING, 0, c, APLOGNO(02616)
1191 "event_resume_suspended: Thread isn't suspended");
1192 return APR_EGENERAL;
1194 apr_atomic_dec32(&suspended_count);
1195 c->suspended_baton = NULL;
1197 apr_thread_mutex_lock(timeout_mutex);
1198 TO_QUEUE_APPEND(write_completion_q, cs);
1199 cs->pfd.reqevents = (
1200 cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN :
1201 APR_POLLOUT) | APR_POLLHUP | APR_POLLERR;
1202 cs->pub.sense = CONN_SENSE_DEFAULT;
1203 apr_pollset_add(event_pollset, &cs->pfd);
1204 apr_thread_mutex_unlock(timeout_mutex);
1209 /* conns_this_child has gone to zero or below. See if the admin coded
1210 "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way
1211 simplifies the hot path in worker_thread */
1212 static void check_infinite_requests(void)
1214 if (ap_max_requests_per_child) {
1215 ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
1216 "Stopping process due to MaxConnectionsPerChild");
1217 signal_threads(ST_GRACEFUL);
1221 conns_this_child = APR_INT32_MAX;
1225 static void close_listeners(int process_slot, int *closed) {
1228 disable_listensocks(process_slot);
1229 ap_close_listeners();
1232 ap_scoreboard_image->parent[process_slot].quiescing = 1;
1233 for (i = 0; i < threads_per_child; ++i) {
1234 ap_update_child_status_from_indexes(process_slot, i,
1235 SERVER_GRACEFUL, NULL);
1237 /* wake up the main thread */
1238 kill(ap_my_pid, SIGTERM);
1242 static void unblock_signal(int sig)
1246 sigemptyset(&sig_mask);
1247 sigaddset(&sig_mask, sig);
1248 #if defined(SIGPROCMASK_SETS_THREAD_MASK)
1249 sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
1251 pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL);
1255 static void dummy_signal_handler(int sig)
1257 /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
1258 * then we don't need this goofy function.
1264 static apr_status_t s_socket_add(void *user_baton,
1268 s_baton_t *s = (s_baton_t*)user_baton;
1269 /* XXXXX: recycle listener_poll_types */
1270 listener_poll_type *pt = ap_malloc(sizeof(*pt));
1272 pt->baton = serf_baton;
1273 pfd->client_data = pt;
1274 return apr_pollset_add(s->pollset, pfd);
1277 static apr_status_t s_socket_remove(void *user_baton,
1281 s_baton_t *s = (s_baton_t*)user_baton;
1282 listener_poll_type *pt = pfd->client_data;
1284 return apr_pollset_remove(s->pollset, pfd);
1288 static apr_status_t init_pollset(apr_pool_t *p)
1291 s_baton_t *baton = NULL;
1294 listener_poll_type *pt;
1297 TO_QUEUE_INIT(write_completion_q);
1298 TO_QUEUE_INIT(keepalive_q);
1299 TO_QUEUE_INIT(linger_q);
1300 TO_QUEUE_INIT(short_linger_q);
1302 listener_pollfd = apr_palloc(p, sizeof(apr_pollfd_t) * num_listensocks);
1303 for (lr = child_listen; lr != NULL; lr = lr->next, i++) {
1305 AP_DEBUG_ASSERT(i < num_listensocks);
1306 pfd = &listener_pollfd[i];
1307 pt = apr_pcalloc(p, sizeof(*pt));
1308 pfd->desc_type = APR_POLL_SOCKET;
1309 pfd->desc.s = lr->sd;
1310 pfd->reqevents = APR_POLLIN;
1312 pt->type = PT_ACCEPT;
1315 pfd->client_data = pt;
1317 apr_socket_opt_set(pfd->desc.s, APR_SO_NONBLOCK, 1);
1318 apr_pollset_add(event_pollset, pfd);
1320 lr->accept_func = ap_unixd_accept;
1324 baton = apr_pcalloc(p, sizeof(*baton));
1325 baton->pollset = event_pollset;
1326 /* TODO: subpools, threads, reuse, etc. -- currently use malloc() inside :( */
1329 g_serf = serf_context_create_ex(baton,
1331 s_socket_remove, p);
1333 ap_register_provider(p, "mpm_serf",
1334 "instance", "0", g_serf);
1341 static apr_status_t push_timer2worker(timer_event_t* te)
1343 return ap_queue_push_timer(worker_queue, te);
1347 * Pre-condition: pfd->cs is neither in pollset nor timeout queue
1348 * this function may only be called by the listener
1350 static apr_status_t push2worker(const apr_pollfd_t * pfd,
1351 apr_pollset_t * pollset)
1353 listener_poll_type *pt = (listener_poll_type *) pfd->client_data;
1354 event_conn_state_t *cs = (event_conn_state_t *) pt->baton;
1357 rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p);
1358 if (rc != APR_SUCCESS) {
1359 /* trash the connection; we couldn't queue the connected
1360 * socket to a worker
1362 apr_bucket_alloc_destroy(cs->bucket_alloc);
1363 apr_socket_close(cs->pfd.desc.s);
1364 ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
1365 ap_server_conf, APLOGNO(00471) "push2worker: ap_queue_push failed");
1366 apr_pool_clear(cs->p);
1367 ap_push_pool(worker_queue_info, cs->p);
1374 * If *have_idle_worker_p == 0, reserve a worker thread, and set
1375 * *have_idle_worker_p = 1.
1376 * If *have_idle_worker_p is already 1, will do nothing.
1377 * If blocking == 1, block if all workers are currently busy.
1378 * If no worker was available immediately, will set *all_busy to 1.
1379 * XXX: If there are no workers, we should not block immediately but
1380 * XXX: close all keep-alive connections first.
1382 static void get_worker(int *have_idle_worker_p, int blocking, int *all_busy)
1386 if (*have_idle_worker_p) {
1387 /* already reserved a worker thread - must have hit a
1388 * transient error on a previous pass
1394 rc = ap_queue_info_wait_for_idler(worker_queue_info, all_busy);
1396 rc = ap_queue_info_try_get_idler(worker_queue_info);
1398 if (rc == APR_SUCCESS) {
1399 *have_idle_worker_p = 1;
1401 else if (!blocking && rc == APR_EAGAIN) {
1404 else if (!APR_STATUS_IS_EOF(rc)) {
1405 ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf, APLOGNO(00472)
1406 "ap_queue_info_wait_for_idler failed. "
1407 "Attempting to shutdown process gracefully");
1408 signal_threads(ST_GRACEFUL);
1412 /* Structures to reuse */
1413 static APR_RING_HEAD(timer_free_ring_t, timer_event_t) timer_free_ring;
1415 static apr_skiplist *timer_skiplist;
1417 static int indexing_comp(void *a, void *b)
1419 apr_time_t t1 = (apr_time_t) (((timer_event_t *) a)->when);
1420 apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when);
1421 AP_DEBUG_ASSERT(t1);
1422 AP_DEBUG_ASSERT(t2);
1423 return ((t1 < t2) ? -1 : ((t1 > t2) ? 1 : 0));
1426 static int indexing_compk(void *ac, void *b)
1428 apr_time_t *t1 = (apr_time_t *) ac;
1429 apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when);
1430 AP_DEBUG_ASSERT(t2);
1431 return ((*t1 < t2) ? -1 : ((*t1 > t2) ? 1 : 0));
1434 static apr_thread_mutex_t *g_timer_skiplist_mtx;
1436 static timer_event_t * event_get_timer_event(apr_time_t t,
1437 ap_mpm_callback_fn_t *cbfn,
1440 apr_pollfd_t **remove)
1443 /* oh yeah, and make locking smarter/fine grained. */
1445 apr_thread_mutex_lock(g_timer_skiplist_mtx);
1447 if (!APR_RING_EMPTY(&timer_free_ring, timer_event_t, link)) {
1448 te = APR_RING_FIRST(&timer_free_ring);
1449 APR_RING_REMOVE(te, link);
1452 te = apr_skiplist_alloc(timer_skiplist, sizeof(timer_event_t));
1453 APR_RING_ELEM_INIT(te, link);
1460 te->remove = remove;
1463 /* Okay, insert sorted by when.. */
1464 apr_skiplist_insert(timer_skiplist, (void *)te);
1466 apr_thread_mutex_unlock(g_timer_skiplist_mtx);
1471 static apr_status_t event_register_timed_callback_ex(apr_time_t t,
1472 ap_mpm_callback_fn_t *cbfn,
1474 apr_pollfd_t **remove)
1476 event_get_timer_event(t + apr_time_now(), cbfn, baton, 1, remove);
1480 static apr_status_t event_register_timed_callback(apr_time_t t,
1481 ap_mpm_callback_fn_t *cbfn,
1484 event_register_timed_callback_ex(t, cbfn, baton, NULL);
1488 static apr_status_t event_register_socket_callback_ex(apr_socket_t **s,
1491 ap_mpm_socket_callback_fn_t *cbfn,
1492 ap_mpm_callback_fn_t *tofn,
1496 apr_status_t rc, final_rc= APR_SUCCESS;
1498 socket_callback_baton_t *scb = apr_pcalloc(p, sizeof(*scb));
1499 listener_poll_type *pt = apr_palloc(p, sizeof(*pt));
1500 apr_pollfd_t **pfds = NULL;
1502 while(s[i] != NULL) {
1507 pfds = apr_pcalloc(p, (nsock+1) * sizeof(apr_pollfd_t*));
1513 scb->user_baton = baton;
1517 for (i = 0; i<nsock; i++) {
1518 pfds[i] = apr_pcalloc(p, sizeof(apr_pollfd_t));
1519 pfds[i]->desc_type = APR_POLL_SOCKET;
1520 pfds[i]->reqevents = (for_read ? APR_POLLIN : APR_POLLOUT) | APR_POLLERR | APR_POLLHUP;
1521 pfds[i]->desc.s = s[i];
1523 pfds[i]->client_data = pt;
1527 /* XXX: This cancel timer event count fire before the pollset is updated */
1528 scb->cancel_event = event_get_timer_event(timeout + apr_time_now(), tofn, baton, 1, pfds);
1530 for (i = 0; i<nsock; i++) {
1531 rc = apr_pollset_add(event_pollset, pfds[i]);
1532 if (rc != APR_SUCCESS) final_rc = rc;
1536 static apr_status_t event_register_socket_callback(apr_socket_t **s,
1539 ap_mpm_socket_callback_fn_t *cbfn,
1542 return event_register_socket_callback_ex(s, p, for_read,
1544 NULL, /* no timeout function */
1546 0 /* no timeout */);
1548 static apr_status_t event_unregister_socket_callback(apr_socket_t **s, apr_pool_t *p)
1551 apr_status_t final_rc = APR_SUCCESS;
1552 apr_pollfd_t **pfds = NULL;
1554 while(s[i] != NULL) {
1559 pfds = apr_palloc(p, nsock * sizeof(apr_pollfd_t*));
1561 for (i = 0; i<nsock; i++) {
1563 pfds[i] = apr_pcalloc(p, sizeof(apr_pollfd_t));
1564 pfds[i]->desc_type = APR_POLL_SOCKET;
1565 pfds[i]->reqevents = APR_POLLERR | APR_POLLHUP;
1566 pfds[i]->desc.s = s[i];
1567 pfds[i]->client_data = NULL;
1568 rc = apr_pollset_remove(event_pollset, pfds[i]);
1569 if (rc != APR_SUCCESS && !APR_STATUS_IS_NOTFOUND(rc)) final_rc = APR_SUCCESS;
1576 * Close socket and clean up if remote closed its end while we were in
1578 * Only to be called in the listener thread;
1579 * Pre-condition: cs is in one of the linger queues and in the pollset
1581 static void process_lingering_close(event_conn_state_t *cs, const apr_pollfd_t *pfd)
1583 apr_socket_t *csd = ap_get_conn_socket(cs->c);
1584 char dummybuf[2048];
1587 struct timeout_queue *q;
1588 q = (cs->pub.state == CONN_STATE_LINGER_SHORT) ? &short_linger_q : &linger_q;
1590 /* socket is already in non-blocking state */
1592 nbytes = sizeof(dummybuf);
1593 rv = apr_socket_recv(csd, dummybuf, &nbytes);
1594 } while (rv == APR_SUCCESS);
1596 if (APR_STATUS_IS_EAGAIN(rv)) {
1600 apr_thread_mutex_lock(timeout_mutex);
1601 rv = apr_pollset_remove(event_pollset, pfd);
1602 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
1604 rv = apr_socket_close(csd);
1605 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
1607 TO_QUEUE_REMOVE(*q, cs);
1608 apr_thread_mutex_unlock(timeout_mutex);
1609 TO_QUEUE_ELEM_INIT(cs);
1611 apr_pool_clear(cs->p);
1612 ap_push_pool(worker_queue_info, cs->p);
1615 /* call 'func' for all elements of 'q' with timeout less than 'timeout_time'.
1616 * Pre-condition: timeout_mutex must already be locked
1617 * Post-condition: timeout_mutex will be locked again
1619 static void process_timeout_queue(struct timeout_queue *q,
1620 apr_time_t timeout_time,
1621 int (*func)(event_conn_state_t *))
1624 event_conn_state_t *first, *cs, *last;
1629 AP_DEBUG_ASSERT(!APR_RING_EMPTY(&q->head, event_conn_state_t, timeout_list));
1631 cs = first = APR_RING_FIRST(&q->head);
1632 while (cs != APR_RING_SENTINEL(&q->head, event_conn_state_t, timeout_list)
1633 && cs->expiration_time < timeout_time) {
1635 rv = apr_pollset_remove(event_pollset, &cs->pfd);
1636 if (rv != APR_SUCCESS && !APR_STATUS_IS_NOTFOUND(rv)) {
1637 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, cs->c, APLOGNO(00473)
1638 "apr_pollset_remove failed");
1640 cs = APR_RING_NEXT(cs, timeout_list);
1646 APR_RING_UNSPLICE(first, last, timeout_list);
1647 AP_DEBUG_ASSERT(q->count >= count);
1649 apr_thread_mutex_unlock(timeout_mutex);
1651 cs = APR_RING_NEXT(first, timeout_list);
1652 TO_QUEUE_ELEM_INIT(first);
1657 apr_thread_mutex_lock(timeout_mutex);
1660 static void socket_callback_wrapper(void *baton){
1661 const apr_pollfd_t *out_pfd = (const apr_pollfd_t *)baton;
1662 socket_callback_baton_t *scb_baton = (socket_callback_baton_t *) ((listener_poll_type *) out_pfd->client_data)->baton;
1663 scb_baton->cbfunc(scb_baton->user_baton, out_pfd);
1666 static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy)
1671 proc_info *ti = dummy;
1672 int process_slot = ti->pid;
1673 apr_pool_t *tpool = apr_thread_pool_get(thd);
1675 apr_pool_t *ptrans; /* Pool for per-transaction stuff */
1677 int have_idle_worker = 0;
1678 event_conn_state_t *cs;
1679 const apr_pollfd_t *out_pfd;
1680 apr_int32_t num = 0;
1681 apr_interval_time_t timeout_interval;
1682 apr_time_t timeout_time = 0, now, last_log;
1683 listener_poll_type *pt;
1684 int closed = 0, listeners_disabled = 0;
1686 last_log = apr_time_now();
1689 /* the following times out events that are really close in the future
1690 * to prevent extra poll calls
1692 * current value is .1 second
1694 #define TIMEOUT_FUDGE_FACTOR 100000
1695 #define EVENT_FUDGE_FACTOR 10000
1697 rc = init_pollset(tpool);
1698 if (rc != APR_SUCCESS) {
1699 ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
1700 "failed to initialize pollset, "
1701 "attempting to shutdown process gracefully");
1702 signal_threads(ST_GRACEFUL);
1706 /* Unblock the signal used to wake this thread up, and set a handler for
1709 unblock_signal(LISTENER_SIGNAL);
1710 apr_signal(LISTENER_SIGNAL, dummy_signal_handler);
1713 int workers_were_busy = 0;
1714 if (listener_may_exit) {
1715 close_listeners(process_slot, &closed);
1716 if (terminate_mode == ST_UNGRACEFUL
1717 || apr_atomic_read32(&connection_count) == 0)
1721 if (conns_this_child <= 0)
1722 check_infinite_requests();
1724 now = apr_time_now();
1725 if (APLOGtrace6(ap_server_conf)) {
1726 /* trace log status every second */
1727 if (now - last_log > apr_time_from_msec(1000)) {
1729 apr_thread_mutex_lock(timeout_mutex);
1730 ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf,
1731 "connections: %u (clogged: %u write-completion: %d "
1732 "keep-alive: %d lingering: %d suspended: %u)",
1733 apr_atomic_read32(&connection_count),
1734 apr_atomic_read32(&clogged_count),
1735 write_completion_q.count,
1737 apr_atomic_read32(&lingering_count),
1738 apr_atomic_read32(&suspended_count));
1739 apr_thread_mutex_unlock(timeout_mutex);
1743 apr_thread_mutex_lock(g_timer_skiplist_mtx);
1744 te = apr_skiplist_peek(timer_skiplist);
1746 if (te->when > now) {
1747 timeout_interval = te->when - now;
1750 timeout_interval = 1;
1754 timeout_interval = apr_time_from_msec(100);
1756 apr_thread_mutex_unlock(g_timer_skiplist_mtx);
1759 rc = serf_context_prerun(g_serf);
1760 if (rc != APR_SUCCESS) {
1761 /* TOOD: what should do here? ugh. */
1764 now = apr_time_now();
1765 apr_thread_mutex_lock(g_timer_skiplist_mtx);
1766 ep = apr_skiplist_peek(timer_skiplist);
1768 if (ep->when < now + EVENT_FUDGE_FACTOR) {
1769 apr_skiplist_pop(timer_skiplist, NULL);
1770 if (!ep->canceled) {
1771 if (ep->remove != NULL) {
1772 for (apr_pollfd_t **pfds = (ep->remove); *pfds != NULL; pfds++) {
1773 apr_pollset_remove(event_pollset, *pfds);
1777 push_timer2worker(ep);
1782 ep = apr_skiplist_peek(timer_skiplist);
1784 apr_thread_mutex_unlock(g_timer_skiplist_mtx);
1786 rc = apr_pollset_poll(event_pollset, timeout_interval, &num, &out_pfd);
1787 if (rc != APR_SUCCESS) {
1788 if (APR_STATUS_IS_EINTR(rc)) {
1791 if (!APR_STATUS_IS_TIMEUP(rc)) {
1792 ap_log_error(APLOG_MARK, APLOG_CRIT, rc, ap_server_conf,
1793 "apr_pollset_poll failed. Attempting to "
1794 "shutdown process gracefully");
1795 signal_threads(ST_GRACEFUL);
1799 if (listener_may_exit) {
1800 close_listeners(process_slot, &closed);
1801 if (terminate_mode == ST_UNGRACEFUL
1802 || apr_atomic_read32(&connection_count) == 0)
1807 pt = (listener_poll_type *) out_pfd->client_data;
1808 if (pt->type == PT_CSD) {
1809 /* one of the sockets is readable */
1810 struct timeout_queue *remove_from_q = &write_completion_q;
1812 cs = (event_conn_state_t *) pt->baton;
1813 switch (cs->pub.state) {
1814 case CONN_STATE_CHECK_REQUEST_LINE_READABLE:
1815 cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
1816 remove_from_q = &keepalive_q;
1817 /* don't wait for a worker for a keepalive request */
1820 case CONN_STATE_WRITE_COMPLETION:
1821 get_worker(&have_idle_worker, blocking,
1822 &workers_were_busy);
1823 apr_thread_mutex_lock(timeout_mutex);
1824 TO_QUEUE_REMOVE(*remove_from_q, cs);
1825 rc = apr_pollset_remove(event_pollset, &cs->pfd);
1828 * Some of the pollset backends, like KQueue or Epoll
1829 * automagically remove the FD if the socket is closed,
1830 * therefore, we can accept _SUCCESS or _NOTFOUND,
1831 * and we still want to keep going
1833 if (rc != APR_SUCCESS && !APR_STATUS_IS_NOTFOUND(rc)) {
1834 ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
1835 "pollset remove failed");
1836 apr_thread_mutex_unlock(timeout_mutex);
1837 start_lingering_close_nonblocking(cs);
1841 apr_thread_mutex_unlock(timeout_mutex);
1842 TO_QUEUE_ELEM_INIT(cs);
1843 /* If we didn't get a worker immediately for a keep-alive
1844 * request, we close the connection, so that the client can
1845 * re-connect to a different process.
1847 if (!have_idle_worker) {
1848 start_lingering_close_nonblocking(cs);
1851 rc = push2worker(out_pfd, event_pollset);
1852 if (rc != APR_SUCCESS) {
1853 ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
1854 ap_server_conf, "push2worker failed");
1857 have_idle_worker = 0;
1860 case CONN_STATE_LINGER_NORMAL:
1861 case CONN_STATE_LINGER_SHORT:
1862 process_lingering_close(cs, out_pfd);
1865 ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
1867 "event_loop: unexpected state %d",
1872 else if (pt->type == PT_ACCEPT) {
1873 /* A Listener Socket is ready for an accept() */
1874 if (workers_were_busy) {
1875 if (!listeners_disabled)
1876 disable_listensocks(process_slot);
1877 listeners_disabled = 1;
1878 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1879 "All workers busy, not accepting new conns "
1882 else if ( (int)apr_atomic_read32(&connection_count)
1883 - (int)apr_atomic_read32(&lingering_count)
1885 + ap_queue_info_get_idlers(worker_queue_info) *
1886 worker_factor / WORKER_FACTOR_SCALE)
1888 if (!listeners_disabled)
1889 disable_listensocks(process_slot);
1890 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1891 "Too many open connections (%u), "
1892 "not accepting new conns in this process",
1893 apr_atomic_read32(&connection_count));
1894 ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
1896 ap_queue_info_get_idlers(worker_queue_info));
1897 listeners_disabled = 1;
1899 else if (listeners_disabled) {
1900 listeners_disabled = 0;
1901 enable_listensocks(process_slot);
1903 if (!listeners_disabled) {
1904 lr = (ap_listen_rec *) pt->baton;
1905 ap_pop_pool(&ptrans, worker_queue_info);
1907 if (ptrans == NULL) {
1908 /* create a new transaction pool for each accepted socket */
1909 apr_allocator_t *allocator;
1911 apr_allocator_create(&allocator);
1912 apr_allocator_max_free_set(allocator,
1914 apr_pool_create_ex(&ptrans, pconf, NULL, allocator);
1915 apr_allocator_owner_set(allocator, ptrans);
1916 if (ptrans == NULL) {
1917 ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
1919 "Failed to create transaction pool");
1920 signal_threads(ST_GRACEFUL);
1924 apr_pool_tag(ptrans, "transaction");
1926 get_worker(&have_idle_worker, 1, &workers_were_busy);
1927 rc = lr->accept_func(&csd, lr, ptrans);
1929 /* later we trash rv and rely on csd to indicate
1932 AP_DEBUG_ASSERT(rc == APR_SUCCESS || !csd);
1934 if (rc == APR_EGENERAL) {
1935 /* E[NM]FILE, ENOMEM, etc */
1936 resource_shortage = 1;
1937 signal_threads(ST_GRACEFUL);
1942 rc = ap_queue_push(worker_queue, csd, NULL, ptrans);
1943 if (rc != APR_SUCCESS) {
1944 /* trash the connection; we couldn't queue the connected
1945 * socket to a worker
1947 apr_socket_close(csd);
1948 ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
1950 "ap_queue_push failed");
1951 apr_pool_clear(ptrans);
1952 ap_push_pool(worker_queue_info, ptrans);
1955 have_idle_worker = 0;
1959 apr_pool_clear(ptrans);
1960 ap_push_pool(worker_queue_info, ptrans);
1963 } /* if:else on pt->type */
1965 else if (pt->type == PT_SERF) {
1966 /* send socket to serf. */
1967 /* XXXX: this doesn't require get_worker() */
1968 serf_event_trigger(g_serf, pt->baton, out_pfd);
1972 else if (pt->type == PT_USER) {
1973 /* masquerade as a timer event that is firing */
1976 socket_callback_baton_t *baton = (socket_callback_baton_t *) pt->baton;
1977 if (baton->cancel_event) {
1978 baton->cancel_event->canceled = 1;
1981 /* We only signal once per N sockets with this baton */
1982 if (!(baton->signaled)) {
1983 baton->signaled = 1;
1984 te = event_get_timer_event(-1 /* fake timer */,
1985 socket_callback_wrapper,
1986 (apr_pollfd_t *)out_pfd,
1987 0, /* don't insert it */
1988 NULL /* no associated socket callback */);
1989 /* remove other sockets in my set */
1990 for (i = 0; i < baton->nsock; i++) {
1991 apr_pollset_remove(event_pollset, baton->pfds[i]);
1994 push_timer2worker(te);
1996 apr_pollset_remove(event_pollset, out_pfd);
2000 } /* while for processing poll */
2002 /* XXX possible optimization: stash the current time for use as
2003 * r->request_time for new requests
2005 now = apr_time_now();
2006 /* we only do this once per 0.1s (TIMEOUT_FUDGE_FACTOR) */
2007 if (now > timeout_time) {
2008 struct process_score *ps;
2009 timeout_time = now + TIMEOUT_FUDGE_FACTOR;
2011 /* handle timed out sockets */
2012 apr_thread_mutex_lock(timeout_mutex);
2014 /* Step 1: keepalive timeouts */
2015 /* If all workers are busy, we kill older keep-alive connections so that they
2016 * may connect to another process.
2018 if (workers_were_busy && keepalive_q.count) {
2019 ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
2020 "All workers are busy, will close %d keep-alive "
2023 process_timeout_queue(&keepalive_q,
2024 timeout_time + ap_server_conf->keep_alive_timeout,
2025 start_lingering_close_nonblocking);
2028 process_timeout_queue(&keepalive_q, timeout_time,
2029 start_lingering_close_nonblocking);
2031 /* Step 2: write completion timeouts */
2032 process_timeout_queue(&write_completion_q, timeout_time,
2033 start_lingering_close_nonblocking);
2034 /* Step 3: (normal) lingering close completion timeouts */
2035 process_timeout_queue(&linger_q, timeout_time, stop_lingering_close);
2036 /* Step 4: (short) lingering close completion timeouts */
2037 process_timeout_queue(&short_linger_q, timeout_time, stop_lingering_close);
2039 ps = ap_get_scoreboard_process(process_slot);
2040 ps->write_completion = write_completion_q.count;
2041 ps->keep_alive = keepalive_q.count;
2042 apr_thread_mutex_unlock(timeout_mutex);
2044 ps->connections = apr_atomic_read32(&connection_count);
2045 ps->suspended = apr_atomic_read32(&suspended_count);
2046 ps->lingering_close = apr_atomic_read32(&lingering_count);
2048 if (listeners_disabled && !workers_were_busy
2049 && (int)apr_atomic_read32(&connection_count)
2050 - (int)apr_atomic_read32(&lingering_count)
2051 < ((int)ap_queue_info_get_idlers(worker_queue_info) - 1)
2052 * worker_factor / WORKER_FACTOR_SCALE + threads_per_child)
2054 listeners_disabled = 0;
2055 enable_listensocks(process_slot);
2058 * XXX: do we need to set some timeout that re-enables the listensocks
2059 * XXX: in case no other event occurs?
2061 } /* listener main loop */
2063 close_listeners(process_slot, &closed);
2064 ap_queue_term(worker_queue);
2066 apr_thread_exit(thd, APR_SUCCESS);
2070 /* XXX For ungraceful termination/restart, we definitely don't want to
2071 * wait for active connections to finish but we may want to wait
2072 * for idle workers to get out of the queue code and release mutexes,
2073 * since those mutexes are cleaned up pretty soon and some systems
2074 * may not react favorably (i.e., segfault) if operations are attempted
2075 * on cleaned-up mutexes.
2077 static void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy)
2079 proc_info *ti = dummy;
2080 int process_slot = ti->pid;
2081 int thread_slot = ti->tid;
2082 apr_socket_t *csd = NULL;
2083 event_conn_state_t *cs;
2084 apr_pool_t *ptrans; /* Pool for per-transaction stuff */
2087 timer_event_t *te = NULL;
2091 ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
2092 ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current();
2093 ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation;
2094 ap_update_child_status_from_indexes(process_slot, thread_slot,
2095 SERVER_STARTING, NULL);
2097 while (!workers_may_exit) {
2099 rv = ap_queue_info_set_idle(worker_queue_info, NULL);
2100 if (rv != APR_SUCCESS) {
2101 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
2102 "ap_queue_info_set_idle failed. Attempting to "
2103 "shutdown process gracefully.");
2104 signal_threads(ST_GRACEFUL);
2110 ap_update_child_status_from_indexes(process_slot, thread_slot,
2111 dying ? SERVER_GRACEFUL : SERVER_READY, NULL);
2113 if (workers_may_exit) {
2118 rv = ap_queue_pop_something(worker_queue, &csd, &cs, &ptrans, &te);
2120 if (rv != APR_SUCCESS) {
2121 /* We get APR_EOF during a graceful shutdown once all the
2122 * connections accepted by this server process have been handled.
2124 if (APR_STATUS_IS_EOF(rv)) {
2127 /* We get APR_EINTR whenever ap_queue_pop() has been interrupted
2128 * from an explicit call to ap_queue_interrupt_all(). This allows
2129 * us to unblock threads stuck in ap_queue_pop() when a shutdown
2132 * If workers_may_exit is set and this is ungraceful termination/
2133 * restart, we are bound to get an error on some systems (e.g.,
2134 * AIX, which sanity-checks mutex operations) since the queue
2135 * may have already been cleaned up. Don't log the "error" if
2136 * workers_may_exit is set.
2138 else if (APR_STATUS_IS_EINTR(rv)) {
2141 /* We got some other error. */
2142 else if (!workers_may_exit) {
2143 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
2144 "ap_queue_pop failed");
2149 te->cbfunc(te->baton);
2151 apr_thread_mutex_lock(g_timer_skiplist_mtx);
2152 APR_RING_INSERT_TAIL(&timer_free_ring, te, timer_event_t, link);
2153 apr_thread_mutex_unlock(g_timer_skiplist_mtx);
2158 worker_sockets[thread_slot] = csd;
2159 process_socket(thd, ptrans, csd, cs, process_slot, thread_slot);
2160 worker_sockets[thread_slot] = NULL;
2164 ap_update_child_status_from_indexes(process_slot, thread_slot,
2165 dying ? SERVER_DEAD :
2167 (request_rec *) NULL);
2169 apr_thread_exit(thd, APR_SUCCESS);
2173 static int check_signal(int signum)
2185 static void create_listener_thread(thread_starter * ts)
2187 int my_child_num = ts->child_num_arg;
2188 apr_threadattr_t *thread_attr = ts->threadattr;
2192 my_info = (proc_info *) ap_malloc(sizeof(proc_info));
2193 my_info->pid = my_child_num;
2194 my_info->tid = -1; /* listener thread doesn't have a thread slot */
2196 rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,
2198 if (rv != APR_SUCCESS) {
2199 ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(00474)
2200 "apr_thread_create: unable to create listener thread");
2201 /* let the parent decide how bad this really is */
2202 clean_child_exit(APEXIT_CHILDSICK);
2204 apr_os_thread_get(&listener_os_thread, ts->listener);
2207 /* XXX under some circumstances not understood, children can get stuck
2208 * in start_threads forever trying to take over slots which will
2209 * never be cleaned up; for now there is an APLOG_DEBUG message issued
2210 * every so often when this condition occurs
2212 static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy)
2214 thread_starter *ts = dummy;
2215 apr_thread_t **threads = ts->threads;
2216 apr_threadattr_t *thread_attr = ts->threadattr;
2217 int child_num_arg = ts->child_num_arg;
2218 int my_child_num = child_num_arg;
2222 int threads_created = 0;
2223 int listener_started = 0;
2225 int prev_threads_created;
2226 int max_recycled_pools = -1;
2227 int good_methods[] = {APR_POLLSET_KQUEUE, APR_POLLSET_PORT, APR_POLLSET_EPOLL};
2229 /* We must create the fd queues before we start up the listener
2230 * and worker threads. */
2231 worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
2232 rv = ap_queue_init(worker_queue, threads_per_child, pchild);
2233 if (rv != APR_SUCCESS) {
2234 ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
2235 "ap_queue_init() failed");
2236 clean_child_exit(APEXIT_CHILDFATAL);
2239 if (ap_max_mem_free != APR_ALLOCATOR_MAX_FREE_UNLIMITED) {
2240 /* If we want to conserve memory, let's not keep an unlimited number of
2241 * pools & allocators.
2242 * XXX: This should probably be a separate config directive
2244 max_recycled_pools = threads_per_child * 3 / 4 ;
2246 rv = ap_queue_info_create(&worker_queue_info, pchild,
2247 threads_per_child, max_recycled_pools);
2248 if (rv != APR_SUCCESS) {
2249 ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
2250 "ap_queue_info_create() failed");
2251 clean_child_exit(APEXIT_CHILDFATAL);
2254 /* Create the timeout mutex and main pollset before the listener
2257 rv = apr_thread_mutex_create(&timeout_mutex, APR_THREAD_MUTEX_DEFAULT,
2259 if (rv != APR_SUCCESS) {
2260 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
2261 "creation of the timeout mutex failed.");
2262 clean_child_exit(APEXIT_CHILDFATAL);
2265 /* Create the main pollset */
2266 for (i = 0; i < sizeof(good_methods) / sizeof(void*); i++) {
2267 rv = apr_pollset_create_ex(&event_pollset,
2268 threads_per_child*2, /* XXX don't we need more, to handle
2269 * connections in K-A or lingering
2272 pchild, APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY | APR_POLLSET_NODEFAULT,
2274 if (rv == APR_SUCCESS) {
2278 if (rv != APR_SUCCESS) {
2279 rv = apr_pollset_create(&event_pollset,
2280 threads_per_child*2, /* XXX don't we need more, to handle
2281 * connections in K-A or lingering
2284 pchild, APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY);
2286 if (rv != APR_SUCCESS) {
2287 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
2288 "apr_pollset_create with Thread Safety failed.");
2289 clean_child_exit(APEXIT_CHILDFATAL);
2292 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02471)
2293 "start_threads: Using %s", apr_pollset_method_name(event_pollset));
2294 worker_sockets = apr_pcalloc(pchild, threads_per_child
2295 * sizeof(apr_socket_t *));
2297 loops = prev_threads_created = 0;
2299 /* threads_per_child does not include the listener thread */
2300 for (i = 0; i < threads_per_child; i++) {
2302 ap_scoreboard_image->servers[child_num_arg][i].status;
2304 if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
2308 my_info = (proc_info *) ap_malloc(sizeof(proc_info));
2309 my_info->pid = my_child_num;
2313 /* We are creating threads right now */
2314 ap_update_child_status_from_indexes(my_child_num, i,
2315 SERVER_STARTING, NULL);
2316 /* We let each thread update its own scoreboard entry. This is
2317 * done because it lets us deal with tid better.
2319 rv = apr_thread_create(&threads[i], thread_attr,
2320 worker_thread, my_info, pchild);
2321 if (rv != APR_SUCCESS) {
2322 ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
2323 "apr_thread_create: unable to create worker thread");
2324 /* let the parent decide how bad this really is */
2325 clean_child_exit(APEXIT_CHILDSICK);
2330 /* Start the listener only when there are workers available */
2331 if (!listener_started && threads_created) {
2332 create_listener_thread(ts);
2333 listener_started = 1;
2337 if (start_thread_may_exit || threads_created == threads_per_child) {
2340 /* wait for previous generation to clean up an entry */
2341 apr_sleep(apr_time_from_sec(1));
2343 if (loops % 120 == 0) { /* every couple of minutes */
2344 if (prev_threads_created == threads_created) {
2345 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2346 "child %" APR_PID_T_FMT " isn't taking over "
2347 "slots very quickly (%d of %d)",
2348 ap_my_pid, threads_created,
2351 prev_threads_created = threads_created;
2355 /* What state should this child_main process be listed as in the
2357 * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
2358 * (request_rec *) NULL);
2360 * This state should be listed separately in the scoreboard, in some kind
2361 * of process_status, not mixed in with the worker threads' status.
2362 * "life_status" is almost right, but it's in the worker's structure, and
2363 * the name could be clearer. gla
2365 apr_thread_exit(thd, APR_SUCCESS);
2369 static void join_workers(apr_thread_t * listener, apr_thread_t ** threads)
2372 apr_status_t rv, thread_rv;
2377 /* deal with a rare timing window which affects waking up the
2378 * listener thread... if the signal sent to the listener thread
2379 * is delivered between the time it verifies that the
2380 * listener_may_exit flag is clear and the time it enters a
2381 * blocking syscall, the signal didn't do any good... work around
2382 * that by sleeping briefly and sending it again
2386 while (iter < 10 && !dying) {
2387 /* listener has not stopped accepting yet */
2388 apr_sleep(apr_time_make(0, 500000));
2393 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00475)
2394 "the listener thread didn't stop accepting");
2397 rv = apr_thread_join(&thread_rv, listener);
2398 if (rv != APR_SUCCESS) {
2399 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00476)
2400 "apr_thread_join: unable to join listener thread");
2405 for (i = 0; i < threads_per_child; i++) {
2406 if (threads[i]) { /* if we ever created this thread */
2407 rv = apr_thread_join(&thread_rv, threads[i]);
2408 if (rv != APR_SUCCESS) {
2409 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00477)
2410 "apr_thread_join: unable to join worker "
2417 static void join_start_thread(apr_thread_t * start_thread_id)
2419 apr_status_t rv, thread_rv;
2421 start_thread_may_exit = 1; /* tell it to give up in case it is still
2422 * trying to take over slots from a
2423 * previous generation
2425 rv = apr_thread_join(&thread_rv, start_thread_id);
2426 if (rv != APR_SUCCESS) {
2427 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00478)
2428 "apr_thread_join: unable to join the start " "thread");
2432 static void child_main(int child_num_arg)
2434 apr_thread_t **threads;
2437 apr_threadattr_t *thread_attr;
2438 apr_thread_t *start_thread_id;
2443 mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
2446 ap_my_pid = getpid();
2447 ap_fatal_signal_child_setup(ap_server_conf);
2448 apr_pool_create(&pchild, pconf);
2450 /* close unused listeners and pods */
2451 for (i = 0; i < num_buckets; i++) {
2452 if (i != bucket[child_num_arg]) {
2455 apr_socket_close(lr->sd);
2459 ap_mpm_podx_close(pod[i]);
2463 /*stuff to do before we switch id's, so we have permissions. */
2464 ap_reopen_scoreboard(pchild, NULL, 0);
2466 if (ap_run_drop_privileges(pchild, ap_server_conf)) {
2467 clean_child_exit(APEXIT_CHILDFATAL);
2470 apr_thread_mutex_create(&g_timer_skiplist_mtx, APR_THREAD_MUTEX_DEFAULT, pchild);
2471 APR_RING_INIT(&timer_free_ring, timer_event_t, link);
2472 apr_pool_create(&pskip, pchild);
2473 apr_skiplist_init(&timer_skiplist, pskip);
2474 apr_skiplist_set_compare(timer_skiplist, indexing_comp, indexing_compk);
2475 ap_run_child_init(pchild, ap_server_conf);
2477 /* done with init critical section */
2479 /* Just use the standard apr_setup_signal_thread to block all signals
2480 * from being received. The child processes no longer use signals for
2481 * any communication with the parent process.
2483 rv = apr_setup_signal_thread();
2484 if (rv != APR_SUCCESS) {
2485 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, APLOGNO(00479)
2486 "Couldn't initialize signal thread");
2487 clean_child_exit(APEXIT_CHILDFATAL);
2490 if (ap_max_requests_per_child) {
2491 conns_this_child = ap_max_requests_per_child;
2494 /* coding a value of zero means infinity */
2495 conns_this_child = APR_INT32_MAX;
2498 /* Setup worker threads */
2500 /* clear the storage; we may not create all our threads immediately,
2501 * and we want a 0 entry to indicate a thread which was not created
2503 threads = ap_calloc(threads_per_child, sizeof(apr_thread_t *));
2504 ts = apr_palloc(pchild, sizeof(*ts));
2506 apr_threadattr_create(&thread_attr, pchild);
2507 /* 0 means PTHREAD_CREATE_JOINABLE */
2508 apr_threadattr_detach_set(thread_attr, 0);
2510 if (ap_thread_stacksize != 0) {
2511 rv = apr_threadattr_stacksize_set(thread_attr, ap_thread_stacksize);
2512 if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
2513 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(02436)
2514 "WARNING: ThreadStackSize of %" APR_SIZE_T_FMT " is "
2515 "inappropriate, using default",
2516 ap_thread_stacksize);
2520 ts->threads = threads;
2521 ts->listener = NULL;
2522 ts->child_num_arg = child_num_arg;
2523 ts->threadattr = thread_attr;
2525 rv = apr_thread_create(&start_thread_id, thread_attr, start_threads,
2527 if (rv != APR_SUCCESS) {
2528 ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(00480)
2529 "apr_thread_create: unable to create worker thread");
2530 /* let the parent decide how bad this really is */
2531 clean_child_exit(APEXIT_CHILDSICK);
2534 mpm_state = AP_MPMQ_RUNNING;
2536 /* If we are only running in one_process mode, we will want to
2537 * still handle signals. */
2539 /* Block until we get a terminating signal. */
2540 apr_signal_thread(check_signal);
2541 /* make sure the start thread has finished; signal_threads()
2542 * and join_workers() depend on that
2544 /* XXX join_start_thread() won't be awakened if one of our
2545 * threads encounters a critical error and attempts to
2546 * shutdown this child
2548 join_start_thread(start_thread_id);
2550 /* helps us terminate a little more quickly than the dispatch of the
2551 * signal thread; beats the Pipe of Death and the browsers
2553 signal_threads(ST_UNGRACEFUL);
2555 /* A terminating signal was received. Now join each of the
2556 * workers to clean them up.
2557 * If the worker already exited, then the join frees
2558 * their resources and returns.
2559 * If the worker hasn't exited, then this blocks until
2560 * they have (then cleans up).
2562 join_workers(ts->listener, threads);
2564 else { /* !one_process */
2565 /* remove SIGTERM from the set of blocked signals... if one of
2566 * the other threads in the process needs to take us down
2567 * (e.g., for MaxConnectionsPerChild) it will send us SIGTERM
2569 unblock_signal(SIGTERM);
2570 apr_signal(SIGTERM, dummy_signal_handler);
2571 /* Watch for any messages from the parent over the POD */
2573 rv = ap_mpm_podx_check(child_pod);
2574 if (rv == AP_MPM_PODX_NORESTART) {
2575 /* see if termination was triggered while we slept */
2576 switch (terminate_mode) {
2578 rv = AP_MPM_PODX_GRACEFUL;
2581 rv = AP_MPM_PODX_RESTART;
2585 if (rv == AP_MPM_PODX_GRACEFUL || rv == AP_MPM_PODX_RESTART) {
2586 /* make sure the start thread has finished;
2587 * signal_threads() and join_workers depend on that
2589 join_start_thread(start_thread_id);
2590 signal_threads(rv ==
2591 AP_MPM_PODX_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL);
2596 /* A terminating signal was received. Now join each of the
2597 * workers to clean them up.
2598 * If the worker already exited, then the join frees
2599 * their resources and returns.
2600 * If the worker hasn't exited, then this blocks until
2601 * they have (then cleans up).
2603 join_workers(ts->listener, threads);
2608 clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);
2611 static int make_child(server_rec * s, int slot)
2615 if (slot + 1 > retained->max_daemons_limit) {
2616 retained->max_daemons_limit = slot + 1;
2619 child_listen = mpm_listen[bucket[slot]];
2620 child_pod = pod[bucket[slot]];
2624 event_note_child_started(slot, getpid());
2629 if ((pid = fork()) == -1) {
2630 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, APLOGNO(00481)
2631 "fork: Unable to fork new process");
2633 /* fork didn't succeed. There's no need to touch the scoreboard;
2634 * if we were trying to replace a failed child process, then
2635 * server_main_loop() marked its workers SERVER_DEAD, and if
2636 * we were trying to replace a child process that exited normally,
2637 * its worker_thread()s left SERVER_DEAD or SERVER_GRACEFUL behind.
2640 /* In case system resources are maxxed out, we don't want
2641 Apache running away with the CPU trying to fork over and
2642 over and over again. */
2643 apr_sleep(apr_time_from_sec(10));
2649 #ifdef HAVE_BINDPROCESSOR
2650 /* By default, AIX binds to a single processor. This bit unbinds
2651 * children which will then bind to another CPU.
2653 int status = bindprocessor(BINDPROCESS, (int) getpid(),
2654 PROCESSOR_CLASS_ANY);
2656 ap_log_error(APLOG_MARK, APLOG_DEBUG, errno,
2657 ap_server_conf, APLOGNO(00482)
2658 "processor unbind failed");
2660 RAISE_SIGSTOP(MAKE_CHILD);
2662 apr_signal(SIGTERM, just_die);
2667 if (ap_scoreboard_image->parent[slot].pid != 0) {
2668 /* This new child process is squatting on the scoreboard
2669 * entry owned by an exiting child process, which cannot
2670 * exit until all active requests complete.
2672 event_note_child_lost_slot(slot, pid);
2674 ap_scoreboard_image->parent[slot].quiescing = 0;
2675 ap_scoreboard_image->parent[slot].not_accepting = 0;
2676 event_note_child_started(slot, pid);
2680 /* start up a bunch of children */
2681 static void startup_children(int number_to_start)
2685 for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
2686 if (ap_scoreboard_image->parent[i].pid != 0) {
2689 bucket[i] = i % num_buckets;
2690 if (make_child(ap_server_conf, i) < 0) {
2697 static void perform_idle_server_maintenance(int child_bucket)
2700 int idle_thread_count;
2704 int totally_free_length = 0;
2705 int free_slots[MAX_SPAWN_RATE];
2708 int active_thread_count = 0;
2710 /* initialize the free_list */
2713 idle_thread_count = 0;
2717 for (i = 0; i < ap_daemons_limit; ++i) {
2718 /* Initialization to satisfy the compiler. It doesn't know
2719 * that threads_per_child is always > 0 */
2720 int status = SERVER_DEAD;
2721 int any_dying_threads = 0;
2722 int any_dead_threads = 0;
2723 int all_dead_threads = 1;
2724 int child_threads_active = 0;
2726 if (i >= retained->max_daemons_limit
2727 && totally_free_length == retained->idle_spawn_rate[child_bucket])
2728 /* short cut if all active processes have been examined and
2729 * enough empty scoreboard slots have been found
2733 ps = &ap_scoreboard_image->parent[i];
2734 for (j = 0; j < threads_per_child; j++) {
2735 ws = &ap_scoreboard_image->servers[i][j];
2736 status = ws->status;
2738 /* XXX any_dying_threads is probably no longer needed GLA */
2739 any_dying_threads = any_dying_threads ||
2740 (status == SERVER_GRACEFUL);
2741 any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
2742 all_dead_threads = all_dead_threads &&
2743 (status == SERVER_DEAD || status == SERVER_GRACEFUL);
2745 /* We consider a starting server as idle because we started it
2746 * at least a cycle ago, and if it still hasn't finished starting
2747 * then we're just going to swamp things worse by forking more.
2748 * So we hopefully won't need to fork more if we count it.
2749 * This depends on the ordering of SERVER_READY and SERVER_STARTING.
2751 if (ps->pid != 0) { /* XXX just set all_dead_threads in outer
2752 for loop if no pid? not much else matters */
2753 if (status <= SERVER_READY && !ps->quiescing && !ps->not_accepting
2754 && ps->generation == retained->my_generation &&
2755 bucket[i] == child_bucket)
2757 ++idle_thread_count;
2759 if (status >= SERVER_READY && status < SERVER_GRACEFUL) {
2760 ++child_threads_active;
2764 active_thread_count += child_threads_active;
2765 if (any_dead_threads
2766 && totally_free_length < retained->idle_spawn_rate[child_bucket]
2767 && free_length < MAX_SPAWN_RATE/num_buckets
2768 && (!ps->pid /* no process in the slot */
2769 || ps->quiescing)) { /* or at least one is going away */
2770 if (all_dead_threads) {
2771 /* great! we prefer these, because the new process can
2772 * start more threads sooner. So prioritize this slot
2773 * by putting it ahead of any slots with active threads.
2775 * first, make room by moving a slot that's potentially still
2776 * in use to the end of the array
2778 free_slots[free_length] = free_slots[totally_free_length];
2779 free_slots[totally_free_length++] = i;
2782 /* slot is still in use - back of the bus
2784 free_slots[free_length] = i;
2788 else if (child_threads_active == threads_per_child) {
2789 had_healthy_child = 1;
2791 /* XXX if (!ps->quiescing) is probably more reliable GLA */
2792 if (!any_dying_threads) {
2798 if (retained->sick_child_detected) {
2799 if (had_healthy_child) {
2800 /* Assume this is a transient error, even though it may not be. Leave
2801 * the server up in case it is able to serve some requests or the
2802 * problem will be resolved.
2804 retained->sick_child_detected = 0;
2807 /* looks like a basket case, as no child ever fully initialized; give up.
2809 shutdown_pending = 1;
2811 ap_log_error(APLOG_MARK, APLOG_ALERT, 0,
2812 ap_server_conf, APLOGNO(02324)
2813 "A resource shortage or other unrecoverable failure "
2814 "was encountered before any child process initialized "
2815 "successfully... httpd is exiting!");
2816 /* the child already logged the failure details */
2821 retained->max_daemons_limit = last_non_dead + 1;
2823 if (idle_thread_count > max_spare_threads/num_buckets) {
2824 /* Kill off one child */
2825 ap_mpm_podx_signal(pod[child_bucket], AP_MPM_PODX_GRACEFUL);
2826 retained->idle_spawn_rate[child_bucket] = 1;
2828 else if (idle_thread_count < min_spare_threads/num_buckets) {
2829 /* terminate the free list */
2830 if (free_length == 0) { /* scoreboard is full, can't fork */
2832 if (active_thread_count >= ap_daemons_limit * threads_per_child) {
2833 if (!retained->maxclients_reported) {
2834 /* only report this condition once */
2835 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(00484)
2836 "server reached MaxRequestWorkers setting, "
2837 "consider raising the MaxRequestWorkers "
2839 retained->maxclients_reported = 1;
2843 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(00485)
2844 "scoreboard is full, not at MaxRequestWorkers");
2846 retained->idle_spawn_rate[child_bucket] = 1;
2849 if (free_length > retained->idle_spawn_rate[child_bucket]) {
2850 free_length = retained->idle_spawn_rate[child_bucket];
2852 if (retained->idle_spawn_rate[child_bucket] >= 8) {
2853 ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00486)
2854 "server seems busy, (you may need "
2855 "to increase StartServers, ThreadsPerChild "
2856 "or Min/MaxSpareThreads), "
2857 "spawning %d children, there are around %d idle "
2858 "threads, and %d total children", free_length,
2859 idle_thread_count, total_non_dead);
2861 for (i = 0; i < free_length; ++i) {
2862 bucket[free_slots[i]] = child_bucket;
2863 make_child(ap_server_conf, free_slots[i]);
2865 /* the next time around we want to spawn twice as many if this
2866 * wasn't good enough, but not if we've just done a graceful
2868 if (retained->hold_off_on_exponential_spawning) {
2869 --retained->hold_off_on_exponential_spawning;
2871 else if (retained->idle_spawn_rate[child_bucket] < MAX_SPAWN_RATE/num_buckets) {
2872 retained->idle_spawn_rate[child_bucket] *= 2;
2877 retained->idle_spawn_rate[child_bucket] = 1;
2881 static void server_main_loop(int remaining_children_to_start)
2883 ap_generation_t old_gen;
2885 apr_exit_why_e exitwhy;
2886 int status, processed_status;
2890 while (!restart_pending && !shutdown_pending) {
2891 ap_wait_or_timeout(&exitwhy, &status, &pid, pconf, ap_server_conf);
2893 if (pid.pid != -1) {
2894 processed_status = ap_process_child_status(&pid, exitwhy, status);
2895 child_slot = ap_find_child_by_pid(&pid);
2896 if (processed_status == APEXIT_CHILDFATAL) {
2897 /* fix race condition found in PR 39311
2898 * A child created at the same time as a graceful happens
2899 * can find the lock missing and create a fatal error.
2900 * It is not fatal for the last generation to be in this state.
2903 || ap_get_scoreboard_process(child_slot)->generation
2904 == retained->my_generation) {
2905 shutdown_pending = 1;
2910 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, APLOGNO(00487)
2911 "Ignoring fatal error in child of previous "
2912 "generation (pid %ld).",
2914 retained->sick_child_detected = 1;
2917 else if (processed_status == APEXIT_CHILDSICK) {
2918 /* tell perform_idle_server_maintenance to check into this
2919 * on the next timer pop
2921 retained->sick_child_detected = 1;
2923 /* non-fatal death... note that it's gone in the scoreboard. */
2924 if (child_slot >= 0) {
2925 for (i = 0; i < threads_per_child; i++)
2926 ap_update_child_status_from_indexes(child_slot, i,
2928 (request_rec *) NULL);
2930 event_note_child_killed(child_slot, 0, 0);
2931 ap_scoreboard_image->parent[child_slot].quiescing = 0;
2932 if (processed_status == APEXIT_CHILDSICK) {
2933 /* resource shortage, minimize the fork rate */
2934 retained->idle_spawn_rate[bucket[child_slot]] = 1;
2936 else if (remaining_children_to_start
2937 && child_slot < ap_daemons_limit) {
2938 /* we're still doing a 1-for-1 replacement of dead
2939 * children with new children
2941 make_child(ap_server_conf, child_slot);
2942 --remaining_children_to_start;
2945 else if (ap_unregister_extra_mpm_process(pid.pid, &old_gen) == 1) {
2947 event_note_child_killed(-1, /* already out of the scoreboard */
2949 if (processed_status == APEXIT_CHILDSICK
2950 && old_gen == retained->my_generation) {
2951 /* resource shortage, minimize the fork rate */
2952 for (i = 0; i < num_buckets; i++) {
2953 retained->idle_spawn_rate[i] = 1;
2956 #if APR_HAS_OTHER_CHILD
2958 else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
2963 else if (retained->is_graceful) {
2964 /* Great, we've probably just lost a slot in the
2965 * scoreboard. Somehow we don't know about this child.
2967 ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
2968 ap_server_conf, APLOGNO(00488)
2969 "long lost child came home! (pid %ld)",
2972 /* Don't perform idle maintenance when a child dies,
2973 * only do it when there's a timeout. Remember only a
2974 * finite number of children can die, and it's pretty
2975 * pathological for a lot to die suddenly.
2979 else if (remaining_children_to_start) {
2980 /* we hit a 1 second timeout in which none of the previous
2981 * generation of children needed to be reaped... so assume
2982 * they're all done, and pick up the slack if any is left.
2984 startup_children(remaining_children_to_start);
2985 remaining_children_to_start = 0;
2986 /* In any event we really shouldn't do the code below because
2987 * few of the servers we just started are in the IDLE state
2988 * yet, so we'd mistakenly create an extra server.
2993 for (i = 0; i < num_buckets; i++) {
2994 perform_idle_server_maintenance(i);
2999 static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
3001 int remaining_children_to_start;
3005 ap_log_pid(pconf, ap_pid_fname);
3007 if (!retained->is_graceful) {
3008 if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
3009 mpm_state = AP_MPMQ_STOPPING;
3012 /* fix the generation number in the global score; we just got a new,
3013 * cleared scoreboard
3015 ap_scoreboard_image->global->running_generation = retained->my_generation;
3018 bucket = apr_palloc(_pconf, sizeof(int) * ap_daemons_limit);
3020 restart_pending = shutdown_pending = 0;
3022 /* Don't thrash... */
3023 if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets)
3024 max_spare_threads = min_spare_threads + threads_per_child * num_buckets;
3026 /* If we're doing a graceful_restart then we're going to see a lot
3027 * of children exiting immediately when we get into the main loop
3028 * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty
3029 * rapidly... and for each one that exits we may start a new one, until
3030 * there are at least min_spare_threads idle threads, counting across
3031 * all children. But we may be permitted to start more children than
3032 * that, so we'll just keep track of how many we're
3033 * supposed to start up without the 1 second penalty between each fork.
3035 remaining_children_to_start = ap_daemons_to_start;
3036 if (remaining_children_to_start > ap_daemons_limit) {
3037 remaining_children_to_start = ap_daemons_limit;
3039 if (!retained->is_graceful) {
3040 startup_children(remaining_children_to_start);
3041 remaining_children_to_start = 0;
3044 /* give the system some time to recover before kicking into
3045 * exponential mode */
3046 retained->hold_off_on_exponential_spawning = 10;
3049 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00489)
3050 "%s configured -- resuming normal operations",
3051 ap_get_server_description());
3052 ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00490)
3053 "Server built: %s", ap_get_server_built());
3054 ap_log_command_line(plog, s);
3057 mpm_state = AP_MPMQ_RUNNING;
3059 server_main_loop(remaining_children_to_start);
3060 mpm_state = AP_MPMQ_STOPPING;
3062 if (shutdown_pending && !retained->is_graceful) {
3063 /* Time to shut down:
3064 * Kill child processes, tell them to call child_exit, etc...
3066 for (i = 0; i < num_buckets; i++) {
3067 ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
3069 ap_reclaim_child_processes(1, /* Start with SIGTERM */
3070 event_note_child_killed);
3073 /* cleanup pid file on normal shutdown */
3074 ap_remove_pid(pconf, ap_pid_fname);
3075 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
3076 ap_server_conf, APLOGNO(00491) "caught SIGTERM, shutting down");
3079 } else if (shutdown_pending) {
3080 /* Time to gracefully shut down:
3081 * Kill child processes, tell them to call child_exit, etc...
3083 int active_children;
3085 apr_time_t cutoff = 0;
3087 /* Close our listeners, and then ask our children to do same */
3088 ap_close_listeners();
3089 for (i = 0; i < num_buckets; i++) {
3090 ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
3092 ap_relieve_child_processes(event_note_child_killed);
3095 /* cleanup pid file on normal shutdown */
3096 ap_remove_pid(pconf, ap_pid_fname);
3097 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00492)
3098 "caught " AP_SIG_GRACEFUL_STOP_STRING
3099 ", shutting down gracefully");
3102 if (ap_graceful_shutdown_timeout) {
3103 cutoff = apr_time_now() +
3104 apr_time_from_sec(ap_graceful_shutdown_timeout);
3107 /* Don't really exit until each child has finished */
3108 shutdown_pending = 0;
3110 /* Pause for a second */
3111 apr_sleep(apr_time_from_sec(1));
3113 /* Relieve any children which have now exited */
3114 ap_relieve_child_processes(event_note_child_killed);
3116 active_children = 0;
3117 for (index = 0; index < ap_daemons_limit; ++index) {
3118 if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
3119 active_children = 1;
3120 /* Having just one child is enough to stay around */
3124 } while (!shutdown_pending && active_children &&
3125 (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
3127 /* We might be here because we received SIGTERM, either
3128 * way, try and make sure that all of our processes are
3131 for (i = 0; i < num_buckets; i++) {
3132 ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
3134 ap_reclaim_child_processes(1, event_note_child_killed);
3139 /* we've been told to restart */
3140 apr_signal(SIGHUP, SIG_IGN);
3143 /* not worth thinking about */
3147 /* advance to the next generation */
3148 /* XXX: we really need to make sure this new generation number isn't in
3149 * use by any of the children.
3151 ++retained->my_generation;
3152 ap_scoreboard_image->global->running_generation = retained->my_generation;
3154 if (retained->is_graceful) {
3155 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00493)
3156 AP_SIG_GRACEFUL_STRING
3157 " received. Doing graceful restart");
3158 /* wake up the children...time to die. But we'll have more soon */
3159 for (i = 0; i < num_buckets; i++) {
3160 ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
3163 /* This is mostly for debugging... so that we know what is still
3164 * gracefully dealing with existing request.
3169 /* Kill 'em all. Since the child acts the same on the parents SIGTERM
3170 * and a SIGHUP, we may as well use the same signal, because some user
3171 * pthreads are stealing signals from us left and right.
3173 for (i = 0; i < num_buckets; i++) {
3174 ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
3177 ap_reclaim_child_processes(1, /* Start with SIGTERM */
3178 event_note_child_killed);
3179 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00494)
3180 "SIGHUP received. Attempting to restart");
3186 /* This really should be a post_config hook, but the error log is already
3187 * redirected by that point, so we need to do this in the open_logs phase.
3189 static int event_open_logs(apr_pool_t * p, apr_pool_t * plog,
3190 apr_pool_t * ptemp, server_rec * s)
3193 int level_flags = 0;
3196 int num_of_cores = 0;
3200 /* the reverse of pre_config, we want this only the first time around */
3201 if (retained->module_loads == 1) {
3203 level_flags |= APLOG_STARTUP;
3206 enable_default_listener = 0;
3208 if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
3209 ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
3210 (startup ? NULL : s),
3211 "no listening sockets available, shutting down");
3215 enable_default_listener = 1;
3216 if (have_so_reuseport) {
3217 #ifdef _SC_NPROCESSORS_ONLN
3218 num_of_cores = sysconf(_SC_NPROCESSORS_ONLN);
3222 if (num_of_cores > 8) {
3223 num_buckets = num_of_cores/8;
3233 ap_duplicate_listeners(ap_server_conf, pconf, num_buckets);
3235 pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
3238 for (i = 0; i < num_buckets; i++) {
3239 if ((rv = ap_mpm_podx_open(pconf, &pod[i]))) {
3240 ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
3241 (startup ? NULL : s),
3242 "could not open pipe-of-death");
3248 srand((unsigned int)apr_time_now());
3252 static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog,
3255 int no_detach, debug, foreground;
3257 const char *userdata_key = "mpm_event_module";
3260 mpm_state = AP_MPMQ_STARTING;
3262 debug = ap_exists_config_define("DEBUG");
3265 foreground = one_process = 1;
3269 one_process = ap_exists_config_define("ONE_PROCESS");
3270 no_detach = ap_exists_config_define("NO_DETACH");
3271 foreground = ap_exists_config_define("FOREGROUND");
3274 /* sigh, want this only the second time around */
3275 retained = ap_retained_data_get(userdata_key);
3277 retained = ap_retained_data_create(userdata_key, sizeof(*retained));
3278 retained->max_daemons_limit = -1;
3280 ++retained->module_loads;
3281 if (retained->module_loads == 2) {
3282 /* test for correct operation of fdqueue */
3283 static apr_uint32_t foo1, foo2;
3285 apr_atomic_set32(&foo1, 100);
3286 foo2 = apr_atomic_add32(&foo1, -10);
3287 if (foo2 != 100 || foo1 != 90) {
3288 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(02405)
3289 "atomics not working as expected - add32 of negative number");
3290 return HTTP_INTERNAL_SERVER_ERROR;
3292 retained->idle_spawn_rate = apr_palloc(pconf, sizeof(int) * num_buckets);
3293 for (i = 0; i< num_buckets; i++) {
3294 retained->idle_spawn_rate[i] = 1;
3296 rv = apr_pollset_create(&event_pollset, 1, plog,
3297 APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY);
3298 if (rv != APR_SUCCESS) {
3299 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00495)
3300 "Couldn't create a Thread Safe Pollset. "
3301 "Is it supported on your platform?"
3302 "Also check system or user limits!");
3303 return HTTP_INTERNAL_SERVER_ERROR;
3305 apr_pollset_destroy(event_pollset);
3307 if (!one_process && !foreground) {
3308 /* before we detach, setup crash handlers to log to errorlog */
3309 ap_fatal_signal_setup(ap_server_conf, pconf);
3310 rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
3311 : APR_PROC_DETACH_DAEMONIZE);
3312 if (rv != APR_SUCCESS) {
3313 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00496)
3314 "apr_proc_detach failed");
3315 return HTTP_INTERNAL_SERVER_ERROR;
3320 parent_pid = ap_my_pid = getpid();
3322 ap_listen_pre_config();
3323 ap_daemons_to_start = DEFAULT_START_DAEMON;
3324 min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
3325 max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
3326 server_limit = DEFAULT_SERVER_LIMIT;
3327 thread_limit = DEFAULT_THREAD_LIMIT;
3328 ap_daemons_limit = server_limit;
3329 threads_per_child = DEFAULT_THREADS_PER_CHILD;
3330 max_workers = ap_daemons_limit * threads_per_child;
3331 had_healthy_child = 0;
3332 ap_extended_status = 0;
3337 static int event_check_config(apr_pool_t *p, apr_pool_t *plog,
3338 apr_pool_t *ptemp, server_rec *s)
3342 /* the reverse of pre_config, we want this only the first time around */
3343 if (retained->module_loads == 1) {
3347 if (server_limit > MAX_SERVER_LIMIT) {
3349 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00497)
3350 "WARNING: ServerLimit of %d exceeds compile-time "
3351 "limit of", server_limit);
3352 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3353 " %d servers, decreasing to %d.",
3354 MAX_SERVER_LIMIT, MAX_SERVER_LIMIT);
3356 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00498)
3357 "ServerLimit of %d exceeds compile-time limit "
3358 "of %d, decreasing to match",
3359 server_limit, MAX_SERVER_LIMIT);
3361 server_limit = MAX_SERVER_LIMIT;
3363 else if (server_limit < 1) {
3365 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00499)
3366 "WARNING: ServerLimit of %d not allowed, "
3367 "increasing to 1.", server_limit);
3369 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00500)
3370 "ServerLimit of %d not allowed, increasing to 1",
3376 /* you cannot change ServerLimit across a restart; ignore
3379 if (!retained->first_server_limit) {
3380 retained->first_server_limit = server_limit;
3382 else if (server_limit != retained->first_server_limit) {
3383 /* don't need a startup console version here */
3384 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00501)
3385 "changing ServerLimit to %d from original value of %d "
3386 "not allowed during restart",
3387 server_limit, retained->first_server_limit);
3388 server_limit = retained->first_server_limit;
3391 if (thread_limit > MAX_THREAD_LIMIT) {
3393 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00502)
3394 "WARNING: ThreadLimit of %d exceeds compile-time "
3395 "limit of", thread_limit);
3396 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3397 " %d threads, decreasing to %d.",
3398 MAX_THREAD_LIMIT, MAX_THREAD_LIMIT);
3400 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00503)
3401 "ThreadLimit of %d exceeds compile-time limit "
3402 "of %d, decreasing to match",
3403 thread_limit, MAX_THREAD_LIMIT);
3405 thread_limit = MAX_THREAD_LIMIT;
3407 else if (thread_limit < 1) {
3409 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00504)
3410 "WARNING: ThreadLimit of %d not allowed, "
3411 "increasing to 1.", thread_limit);
3413 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00505)
3414 "ThreadLimit of %d not allowed, increasing to 1",
3420 /* you cannot change ThreadLimit across a restart; ignore
3423 if (!retained->first_thread_limit) {
3424 retained->first_thread_limit = thread_limit;
3426 else if (thread_limit != retained->first_thread_limit) {
3427 /* don't need a startup console version here */
3428 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00506)
3429 "changing ThreadLimit to %d from original value of %d "
3430 "not allowed during restart",
3431 thread_limit, retained->first_thread_limit);
3432 thread_limit = retained->first_thread_limit;
3435 if (threads_per_child > thread_limit) {
3437 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00507)
3438 "WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
3439 "of", threads_per_child);
3440 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3441 " %d threads, decreasing to %d.",
3442 thread_limit, thread_limit);
3443 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3444 " To increase, please see the ThreadLimit "
3447 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00508)
3448 "ThreadsPerChild of %d exceeds ThreadLimit "
3449 "of %d, decreasing to match",
3450 threads_per_child, thread_limit);
3452 threads_per_child = thread_limit;
3454 else if (threads_per_child < 1) {
3456 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00509)
3457 "WARNING: ThreadsPerChild of %d not allowed, "
3458 "increasing to 1.", threads_per_child);
3460 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00510)
3461 "ThreadsPerChild of %d not allowed, increasing to 1",
3464 threads_per_child = 1;
3467 if (max_workers < threads_per_child) {
3469 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00511)
3470 "WARNING: MaxRequestWorkers of %d is less than "
3471 "ThreadsPerChild of", max_workers);
3472 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3473 " %d, increasing to %d. MaxRequestWorkers must be at "
3475 threads_per_child, threads_per_child);
3476 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3477 " as the number of threads in a single server.");
3479 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00512)
3480 "MaxRequestWorkers of %d is less than ThreadsPerChild "
3481 "of %d, increasing to match",
3482 max_workers, threads_per_child);
3484 max_workers = threads_per_child;
3487 ap_daemons_limit = max_workers / threads_per_child;
3489 if (max_workers % threads_per_child) {
3490 int tmp_max_workers = ap_daemons_limit * threads_per_child;
3493 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00513)
3494 "WARNING: MaxRequestWorkers of %d is not an integer "
3495 "multiple of", max_workers);
3496 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3497 " ThreadsPerChild of %d, decreasing to nearest "
3498 "multiple %d,", threads_per_child,
3500 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3501 " for a maximum of %d servers.",
3504 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00514)
3505 "MaxRequestWorkers of %d is not an integer multiple "
3506 "of ThreadsPerChild of %d, decreasing to nearest "
3507 "multiple %d", max_workers, threads_per_child,
3510 max_workers = tmp_max_workers;
3513 if (ap_daemons_limit > server_limit) {
3515 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00515)
3516 "WARNING: MaxRequestWorkers of %d would require %d "
3517 "servers and ", max_workers, ap_daemons_limit);
3518 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3519 " would exceed ServerLimit of %d, decreasing to %d.",
3520 server_limit, server_limit * threads_per_child);
3521 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3522 " To increase, please see the ServerLimit "
3525 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00516)
3526 "MaxRequestWorkers of %d would require %d servers and "
3527 "exceed ServerLimit of %d, decreasing to %d",
3528 max_workers, ap_daemons_limit, server_limit,
3529 server_limit * threads_per_child);
3531 ap_daemons_limit = server_limit;
3534 /* ap_daemons_to_start > ap_daemons_limit checked in ap_mpm_run() */
3535 if (ap_daemons_to_start < 0) {
3537 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00517)
3538 "WARNING: StartServers of %d not allowed, "
3539 "increasing to 1.", ap_daemons_to_start);
3541 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00518)
3542 "StartServers of %d not allowed, increasing to 1",
3543 ap_daemons_to_start);
3545 ap_daemons_to_start = 1;
3548 if (min_spare_threads < 1) {
3550 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00519)
3551 "WARNING: MinSpareThreads of %d not allowed, "
3552 "increasing to 1", min_spare_threads);
3553 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3554 " to avoid almost certain server failure.");
3555 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
3556 " Please read the documentation.");
3558 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00520)
3559 "MinSpareThreads of %d not allowed, increasing to 1",
3562 min_spare_threads = 1;
3565 /* max_spare_threads < min_spare_threads + threads_per_child
3566 * checked in ap_mpm_run()
3572 static void event_hooks(apr_pool_t * p)
3574 /* Our open_logs hook function must run before the core's, or stderr
3575 * will be redirected to a file, and the messages won't print to the
3578 static const char *const aszSucc[] = { "core.c", NULL };
3582 ap_hook_open_logs(event_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
3583 /* we need to set the MPM state before other pre-config hooks use MPM query
3584 * to retrieve it, so register as REALLY_FIRST
3586 ap_hook_pre_config(event_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
3587 ap_hook_check_config(event_check_config, NULL, NULL, APR_HOOK_MIDDLE);
3588 ap_hook_mpm(event_run, NULL, NULL, APR_HOOK_MIDDLE);
3589 ap_hook_mpm_query(event_query, NULL, NULL, APR_HOOK_MIDDLE);
3590 ap_hook_mpm_register_timed_callback(event_register_timed_callback, NULL, NULL,
3592 ap_hook_mpm_register_socket_callback(event_register_socket_callback, NULL, NULL,
3594 ap_hook_mpm_register_socket_callback_timeout(event_register_socket_callback_ex, NULL, NULL,
3596 ap_hook_mpm_unregister_socket_callback(event_unregister_socket_callback, NULL, NULL,
3598 ap_hook_pre_read_request(event_pre_read_request, NULL, NULL, APR_HOOK_MIDDLE);
3599 ap_hook_mpm_get_name(event_get_name, NULL, NULL, APR_HOOK_MIDDLE);
3600 ap_hook_mpm_resume_suspended(event_resume_suspended, NULL, NULL, APR_HOOK_MIDDLE);
3603 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
3606 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3611 ap_daemons_to_start = atoi(arg);
3615 static const char *set_min_spare_threads(cmd_parms * cmd, void *dummy,
3618 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3623 min_spare_threads = atoi(arg);
3627 static const char *set_max_spare_threads(cmd_parms * cmd, void *dummy,
3630 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3635 max_spare_threads = atoi(arg);
3639 static const char *set_max_workers(cmd_parms * cmd, void *dummy,
3642 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3646 if (!strcasecmp(cmd->cmd->name, "MaxClients")) {
3647 ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(00521)
3648 "MaxClients is deprecated, use MaxRequestWorkers "
3651 max_workers = atoi(arg);
3655 static const char *set_threads_per_child(cmd_parms * cmd, void *dummy,
3658 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3663 threads_per_child = atoi(arg);
3666 static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
3668 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3673 server_limit = atoi(arg);
3677 static const char *set_thread_limit(cmd_parms * cmd, void *dummy,
3680 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3685 thread_limit = atoi(arg);
3689 static const char *set_worker_factor(cmd_parms * cmd, void *dummy,
3694 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3699 val = strtod(arg, &endptr);
3701 return "error parsing value";
3704 return "AsyncRequestWorkerFactor argument must be a positive number";
3706 worker_factor = val * WORKER_FACTOR_SCALE;
3707 if (worker_factor == 0)
3713 static const command_rec event_cmds[] = {
3715 AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
3716 "Number of child processes launched at server startup"),
3717 AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
3718 "Maximum number of child processes for this run of Apache"),
3719 AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
3720 "Minimum number of idle threads, to handle request spikes"),
3721 AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
3722 "Maximum number of idle threads"),
3723 AP_INIT_TAKE1("MaxClients", set_max_workers, NULL, RSRC_CONF,
3724 "Deprecated name of MaxRequestWorkers"),
3725 AP_INIT_TAKE1("MaxRequestWorkers", set_max_workers, NULL, RSRC_CONF,
3726 "Maximum number of threads alive at the same time"),
3727 AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
3728 "Number of threads each child creates"),
3729 AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
3730 "Maximum number of worker threads per child process for this "
3731 "run of Apache - Upper limit for ThreadsPerChild"),
3732 AP_INIT_TAKE1("AsyncRequestWorkerFactor", set_worker_factor, NULL, RSRC_CONF,
3733 "How many additional connects will be accepted per idle "
3735 AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
3739 AP_DECLARE_MODULE(mpm_event) = {
3741 NULL, /* hook to run before apache parses args */
3742 NULL, /* create per-directory config structure */
3743 NULL, /* merge per-directory config structures */
3744 NULL, /* create per-server config structure */
3745 NULL, /* merge per-server config structures */
3746 event_cmds, /* command apr_table_t */
3747 event_hooks /* register_hooks */