event.c revision f6aa8572a3986fcc2cfed30ce1730aca0c14df72
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * applicable.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Licensed under the Apache License, Version 2.0 (the "License");
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * you may not use this file except in compliance with the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * You may obtain a copy of the License at
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Unless required by applicable law or agreed to in writing, software
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * distributed under the License is distributed on an "AS IS" BASIS,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * See the License for the specific language governing permissions and
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * limitations under the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * This MPM tries to fix the 'keep alive problem' in HTTP.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * After a client completes the first request, the client can keep the
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * connection open to send more requests with the same socket. This can save
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * signifigant overhead in creating TCP connections. However, the major
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * disadvantage is that Apache traditionally keeps an entire child
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * process/thread waiting for data from the client. To solve this problem,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * this MPM has a dedicated thread for handling both the Listenting sockets,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * and all sockets that are in a Keep Alive status.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * The MPM assumes the underlying apr_pollset implmentation is somewhat
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * threadsafe. This currently is only compatible with KQueue and EPoll. This
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * enables the MPM to avoid extra high level locking or having to wake up the
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * listener thread when a keep-alive socket needs to be sent to it.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * This MPM not preform well on older platforms that do not have very good
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * threading, like Linux with a 2.4 kernel, but this does not matter, since we
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * require EPoll or KQueue.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * For FreeBSD, use 5.3. It is possible to run this MPM on FreeBSD 5.2.1, if
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * you use libkse (see `man libmap.conf`).
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * For NetBSD, use at least 2.0.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * For Linux, you should use a 2.6 kernel, and make sure your glibc has epoll
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * support compiled in.
f4c310fd2555c6faca1f980f00b161eadb089023gstein#error The Event MPM requires APR threads, but they are unavailable.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Limit on the total --- clients will be locked out if more servers than
f4c310fd2555c6faca1f980f00b161eadb089023gstein * this are needed. It is intended solely to keep the server from crashing
f4c310fd2555c6faca1f980f00b161eadb089023gstein * when things get out of hand.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We keep a hard maximum number of servers, for two reasons --- first off,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in case something goes seriously wrong, we want to stop the fork bomb
f4c310fd2555c6faca1f980f00b161eadb089023gstein * short of actually crashing the machine we're running on by filling some
f4c310fd2555c6faca1f980f00b161eadb089023gstein * kernel table. Secondly, it keeps the size of the scoreboard file small
f4c310fd2555c6faca1f980f00b161eadb089023gstein * enough that we can read the whole thing without worrying too much about
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the overhead.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
f4c310fd2555c6faca1f980f00b161eadb089023gstein * some sort of compile-time limit to help catch typos.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Limit on the threads per process. Clients will be locked out if more than
f4c310fd2555c6faca1f980f00b161eadb089023gstein * this are needed.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We keep this for one reason it keeps the size of the scoreboard file small
f4c310fd2555c6faca1f980f00b161eadb089023gstein * enough that we can read the whole thing without worrying too much about
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the overhead.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
f4c310fd2555c6faca1f980f00b161eadb089023gstein * some sort of compile-time limit to help catch typos.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Actual definitions of config globals
f4c310fd2555c6faca1f980f00b161eadb089023gsteinint ap_threads_per_child = 0; /* Worker threads per child */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int min_spare_threads = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int max_spare_threads = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int ap_daemons_limit = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int first_server_limit = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int first_thread_limit = 0;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic int dying = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int workers_may_exit = 0;
fe4d394397840dd4823e3d6fc5affc1ab395e161gsteinstatic int listener_may_exit = 0;
fe4d394397840dd4823e3d6fc5affc1ab395e161gsteinstatic int num_listensocks = 0;
fe4d394397840dd4823e3d6fc5affc1ab395e161gsteinstatic int resource_shortage = 0;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/* The structure used to pass unique initialization info to each thread */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmtypedef struct
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Structure used to pass information to the thread responsible for
f4c310fd2555c6faca1f980f00b161eadb089023gstein * creating the rest of the threads.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmtypedef struct
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef enum
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct
f4c310fd2555c6faca1f980f00b161eadb089023gstein int status; /*XXX what is this for? 0 and 1 don't make it clear */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
f4c310fd2555c6faca1f980f00b161eadb089023gstein * The max child slot ever assigned, preserved across restarts. Necessary
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
f4c310fd2555c6faca1f980f00b161eadb089023gstein * use this value to optimize routines that have to scan the entire
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * scoreboard.
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* *Non*-shared http_main globals... */
709df1e1c2e1710570f8cb4209497e88662829c3gstein/* The worker MPM respects a couple of runtime flags that can aid
709df1e1c2e1710570f8cb4209497e88662829c3gstein * in debugging. Setting the -DNO_DETACH flag will prevent the root process
f4c310fd2555c6faca1f980f00b161eadb089023gstein * from detaching from its controlling terminal. Additionally, setting
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
709df1e1c2e1710570f8cb4209497e88662829c3gstein * child_main loop running in the process which originally started up.
709df1e1c2e1710570f8cb4209497e88662829c3gstein * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * early in standalone_main; just continue through. This is the server
709df1e1c2e1710570f8cb4209497e88662829c3gstein * trying to kill off any child processes which it might have lying
709df1e1c2e1710570f8cb4209497e88662829c3gstein * around --- Apache doesn't keep track of their pids, it just sends
709df1e1c2e1710570f8cb4209497e88662829c3gstein * SIGHUP to the process group, ignoring it in the root process.
709df1e1c2e1710570f8cb4209497e88662829c3gstein * Continue through and you'll be fine.).
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int one_process = 0;
709df1e1c2e1710570f8cb4209497e88662829c3gsteinstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
709df1e1c2e1710570f8cb4209497e88662829c3gstein thread. Use this instead */
709df1e1c2e1710570f8cb4209497e88662829c3gstein/* The LISTENER_SIGNAL signal will be sent from the main thread to the
709df1e1c2e1710570f8cb4209497e88662829c3gstein * listener thread to wake it up for graceful termination (what a child
f4c310fd2555c6faca1f980f00b161eadb089023gstein * process from an old generation does when the admin does "apachectl
709df1e1c2e1710570f8cb4209497e88662829c3gstein * graceful"). This signal will be blocked in all threads of a child
709df1e1c2e1710570f8cb4209497e88662829c3gstein * process except for the listener thread.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/* An array of socket descriptors in use by each thread used to
709df1e1c2e1710570f8cb4209497e88662829c3gstein * perform a non-graceful (forced) shutdown of the server.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void close_worker_sockets(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < ap_threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void wakeup_listener(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX there is an obscure path that this doesn't handle perfectly:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * right after listener thread is created but before
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener_os_thread is set, the first worker thread hits an
f4c310fd2555c6faca1f980f00b161eadb089023gstein * error and starts graceful termination
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
f4c310fd2555c6faca1f980f00b161eadb089023gstein * platforms and wake up the listener thread since it is the only thread
f4c310fd2555c6faca1f980f00b161eadb089023gstein * with SIGHUP unblocked, but that doesn't work on Linux
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* in case we weren't called from the listener thread, wake up the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener thread
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* for ungraceful termination, let the workers exit now;
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein * for graceful termination, the listener thread will notify the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * workers to exit once it has stopped accepting new connections
f4c310fd2555c6faca1f980f00b161eadb089023gstein close_worker_sockets(); /* forcefully kill all current connections */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinAP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* a clean exit from a child with proper cleanup */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void clean_child_exit(int code) __attribute__ ((noreturn));
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*****************************************************************
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Connection structures and accounting...
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* volatile just in case */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int volatile shutdown_pending;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int volatile restart_pending;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int volatile is_graceful;
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic volatile int child_fatal;
f4c310fd2555c6faca1f980f00b161eadb089023gstein * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein * functions to initiate shutdown or restart without relying on signals.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Previously this was initiated in sig_term() and restart() signal handlers,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * but we want to be able to start a shutdown/restart from other sources --
f4c310fd2555c6faca1f980f00b161eadb089023gstein * e.g. on Win32, from the service manager. Now the service manager can
f4c310fd2555c6faca1f980f00b161eadb089023gstein * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
f4c310fd2555c6faca1f980f00b161eadb089023gstein * these functions can also be called by the child processes, since global
f4c310fd2555c6faca1f980f00b161eadb089023gstein * variables are no longer used to pass on the required action to the parent.
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein * These should only be called from the parent process itself, since the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * parent process will use the shutdown_pending and restart_pending variables
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to determine whether to shutdown or restart. The child process should
f4c310fd2555c6faca1f980f00b161eadb089023gstein * call signal_parent() directly to tell the parent to die -- this will
f4c310fd2555c6faca1f980f00b161eadb089023gstein * cause neither of those variable to be set, which the parent will
f4c310fd2555c6faca1f980f00b161eadb089023gstein * assume means something serious is wrong (which it will be, for the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * child to force an exit) and so do an exit anyway.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Um, is this _probably_ not an error, if the user has
f4c310fd2555c6faca1f980f00b161eadb089023gstein * tried to do a shutdown twice quickly, so we won't
f4c310fd2555c6faca1f980f00b161eadb089023gstein * worry about reporting it.
d839a9822ee53ce00da24c15f2d9fe054233d342gstein/* do a graceful restart if graceful == 1 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Probably not an error - don't bother reporting it */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void set_signals(void)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGTERM)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGINT)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGXCPU)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGXFSZ)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGPIPE)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
f4c310fd2555c6faca1f980f00b161eadb089023gstein * processing one */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "sigaction(SIGHUP)");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGXCPU */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGXFSZ */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGHUP */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* AP_SIG_GRACEFUL */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* AP_SIG_GRACEFUL_STOP */
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif /* SIGPIPE */
50bd75672ef114fb839dd9643c192b432fdf344cgstein/*****************************************************************
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Here follows a long bunch of generic server bookkeeping stuff...
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX this is really a bad confusing obsolete name
f4c310fd2555c6faca1f980f00b161eadb089023gstein * maybe it should be ap_mpm_process_exiting?
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* note: for a graceful termination, listener_may_exit will be set before
f4c310fd2555c6faca1f980f00b161eadb089023gstein * workers_may_exit, so check listener_may_exit
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/*****************************************************************
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Child process main loop.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int process_socket(apr_pool_t * p, apr_socket_t * sock,
f4c310fd2555c6faca1f980f00b161eadb089023gstein long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
f4c310fd2555c6faca1f980f00b161eadb089023gstein c = ap_run_create_connection(p, ap_server_conf, sock,
50bd75672ef114fb839dd9643c192b432fdf344cgstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
50bd75672ef114fb839dd9643c192b432fdf344cgstein "process_socket: connection aborted");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * XXX If the platform does not have a usable way of bundling
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * accept() with a socket readability check, like Win32,
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * and there are measurable delays before the
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * socket is readable due to the first data packet arriving,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * it might be better to create the cs on the listener thread,
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * set the state to CONN_STATE_CHECK_REQUEST_LINE_READABLE,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and give it to the event thread.
50bd75672ef114fb839dd9643c192b432fdf344cgstein * FreeBSD users will want to enable the HTTP accept filter
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * module in their kernel for the highest performance
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * When the accept filter is active, sockets are kept in the
ba8574a7fe6f1c3405982bb856591b5f13fe205agstein * kernel until a HTTP request is received.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* state will be updated upon return
f4c310fd2555c6faca1f980f00b161eadb089023gstein * fall thru to either wait for readability/timeout or
f4c310fd2555c6faca1f980f00b161eadb089023gstein * do lingering close
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (cs->state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm listener_poll_type *pt = (listener_poll_type *) cs->pfd.client_data;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* It greatly simplifies the logic to use a single timeout value here
f4c310fd2555c6faca1f980f00b161eadb089023gstein * because the new element can just be added to the end of the list and
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * it will stay sorted in expiration time sequence. If brand new
f4c310fd2555c6faca1f980f00b161eadb089023gstein * sockets are sent to the event thread for a readability check, this
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein * will be a slight behavior change - they use the non-keepalive
26250b0077972bf21b6d8a8d23772a4cf53f9477gstein * timeout today. With a normal client, the socket will be readable in
f4c310fd2555c6faca1f980f00b161eadb089023gstein * a few milliseconds anyway.
f4c310fd2555c6faca1f980f00b161eadb089023gstein cs->expiration_time = ap_server_conf->keep_alive_timeout + time_now;
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_RING_INSERT_TAIL(&timeout_head, cs, conn_state_t, timeout_list);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Add work to pollset. These are always read events */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "process_socket: apr_pollset_add failure");
50bd75672ef114fb839dd9643c192b432fdf344cgstein/* requests_this_child has gone to zero or below. See if the admin coded
50bd75672ef114fb839dd9643c192b432fdf344cgstein "MaxRequestsPerChild 0", and keep going in that case. Doing it this way
50bd75672ef114fb839dd9643c192b432fdf344cgstein simplifies the hot path in worker_thread */
50bd75672ef114fb839dd9643c192b432fdf344cgsteinstatic void check_infinite_requests(void)
50bd75672ef114fb839dd9643c192b432fdf344cgstein /* wow! if you're executing this code, you may have set a record.
50bd75672ef114fb839dd9643c192b432fdf344cgstein * either this child process has served over 2 billion requests, or
50bd75672ef114fb839dd9643c192b432fdf344cgstein * you're running a threaded 2.0 on a 16 bit machine.
50bd75672ef114fb839dd9643c192b432fdf344cgstein * I'll buy pizza and beers at Apachecon for the first person to do
50bd75672ef114fb839dd9643c192b432fdf344cgstein * the former without cheating (dorking with INT_MAX, or running with
50bd75672ef114fb839dd9643c192b432fdf344cgstein * uncommitted performance patches, for example).
50bd75672ef114fb839dd9643c192b432fdf344cgstein * for the latter case, you probably deserve a beer too. Greg Ames
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * then we don't need this goofy function.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t push2worker(const apr_pollfd_t * pfd,
f4c310fd2555c6faca1f980f00b161eadb089023gstein listener_poll_type *pt = (listener_poll_type *) pfd->client_data;
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Some of the pollset backends, like KQueue or Epoll
f4c310fd2555c6faca1f980f00b161eadb089023gstein * automagically remove the FD if the socket is closed,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * therefore, we can accept _SUCCESS or _NOTFOUND,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and we still want to keep going
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* trash the connection; we couldn't queue the connected
f4c310fd2555c6faca1f980f00b161eadb089023gstein * socket to a worker
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_server_conf, "push2worker: ap_queue_push failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* get_worker:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * reserve a worker thread, block if all are currently busy.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * this prevents the worker queue from overflowing and lets
f4c310fd2555c6faca1f980f00b161eadb089023gstein * other processes accept new connections in the mean time.
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = ap_queue_info_wait_for_idler(worker_queue_info);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_info_wait_for_idler failed. "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Attempting to shutdown process gracefully");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* already reserved a worker thread - must have hit a
f4c310fd2555c6faca1f980f00b161eadb089023gstein * transient error on a previous pass
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *listener_thread(apr_thread_t * thd, void *dummy)
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *ptrans; /* Pool for per-transaction stuff */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We set this to force apr_pollset to wakeup if there hasn't been any IO
f4c310fd2555c6faca1f980f00b161eadb089023gstein * on any of its sockets. This allows sockets to have been added
f4c310fd2555c6faca1f980f00b161eadb089023gstein * when no other keepalive operations where going on.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * current value is 1 second
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* the following times out events that are really close in the future
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to prevent extra poll calls
f4c310fd2555c6faca1f980f00b161eadb089023gstein * current value is .1 second
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* POLLSET_SCALE_FACTOR * ap_threads_per_child sets the size of
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the pollset. I've seen 15 connections per active worker thread
f4c310fd2555c6faca1f980f00b161eadb089023gstein * running SPECweb99.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * However, with the newer apr_pollset, this is the number of sockets that
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we will return to any *one* call to poll(). Therefore, there is no
f4c310fd2555c6faca1f980f00b161eadb089023gstein * reason to make it more than ap_threads_per_child.
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = apr_thread_mutex_create(&timeout_mutex, APR_THREAD_MUTEX_DEFAULT,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "creation of the timeout mutex failed. Attempting to "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "shutdown process gracefully");
f4c310fd2555c6faca1f980f00b161eadb089023gstein APR_RING_INIT(&timeout_head, conn_state_t, timeout_list);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Create the main pollset */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm "apr_pollset_create with Thread Safety failed. "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Attempting to shutdown process gracefully");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Unblock the signal used to wake this thread up, and set a handler for
f4c310fd2555c6faca1f980f00b161eadb089023gstein rc = apr_pollset_poll(event_pollset, timeout_interval, &num,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_pollset_poll failed. Attempting to "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "shutdown process gracefully");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* one of the sockets is readable */
f4c310fd2555c6faca1f980f00b161eadb089023gstein "event_loop: unexpected state %d",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* A Listener Socket is ready for an accept() */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* create a new transaction pool for each accepted socket */
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Failed to create transaction pool");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* later we trash rv and rely on csd to indicate
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* E[NM]FILE, ENOMEM, etc */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* trash the connection; we couldn't queue the connected
f4c310fd2555c6faca1f980f00b161eadb089023gstein * socket to a worker
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_push failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein } /* if:else on pt->type */
f4c310fd2555c6faca1f980f00b161eadb089023gstein } /* while for processing poll */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX possible optimization: stash the current time for use as
f4c310fd2555c6faca1f980f00b161eadb089023gstein * r->request_time for new requests
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* handle timed out sockets */
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (!APR_RING_EMPTY(&timeout_head, conn_state_t, timeout_list)
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* XXX return NULL looks wrong - not an init failure
f4c310fd2555c6faca1f980f00b161eadb089023gstein * that bypasses all the cleanup outside the main loop
f4c310fd2555c6faca1f980f00b161eadb089023gstein * break seems more like it
f4c310fd2555c6faca1f980f00b161eadb089023gstein * need to evaluate seriousness of push2worker failures
f4c310fd2555c6faca1f980f00b161eadb089023gstein } /* listener main loop */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[process_slot].quiescing = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* wake up the main thread */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* XXX For ungraceful termination/restart, we definitely don't want to
f4c310fd2555c6faca1f980f00b161eadb089023gstein * wait for active connections to finish but we may want to wait
f4c310fd2555c6faca1f980f00b161eadb089023gstein * for idle workers to get out of the queue code and release mutexes,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * since those mutexes are cleaned up pretty soon and some systems
f4c310fd2555c6faca1f980f00b161eadb089023gstein * may not react favorably (i.e., segfault) if operations are attempted
f4c310fd2555c6faca1f980f00b161eadb089023gstein * on cleaned-up mutexes.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy)
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *ptrans; /* Pool for per-transaction stuff */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->servers[process_slot][thread_slot].generation = ap_my_generation;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(process_slot, thread_slot,
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_queue_info_set_idle(worker_queue_info, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_info_set_idle failed. Attempting to "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "shutdown process gracefully.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(process_slot, thread_slot,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We get APR_EOF during a graceful shutdown once all the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * connections accepted by this server process have been handled.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We get APR_EINTR whenever ap_queue_pop() has been interrupted
f4c310fd2555c6faca1f980f00b161eadb089023gstein * from an explicit call to ap_queue_interrupt_all(). This allows
f4c310fd2555c6faca1f980f00b161eadb089023gstein * us to unblock threads stuck in ap_queue_pop() when a shutdown
f4c310fd2555c6faca1f980f00b161eadb089023gstein * is pending.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If workers_may_exit is set and this is ungraceful termination/
f4c310fd2555c6faca1f980f00b161eadb089023gstein * restart, we are bound to get an error on some systems (e.g.,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * AIX, which sanity-checks mutex operations) since the queue
f4c310fd2555c6faca1f980f00b161eadb089023gstein * may have already been cleaned up. Don't log the "error" if
f4c310fd2555c6faca1f980f00b161eadb089023gstein * workers_may_exit is set.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We got some other error. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_pop failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = process_socket(ptrans, csd, cs, process_slot, thread_slot);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(process_slot, thread_slot,
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void create_listener_thread(thread_starter * ts)
f4c310fd2555c6faca1f980f00b161eadb089023gstein my_info->tid = -1; /* listener thread doesn't have a thread slot */
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_thread_create: unable to create listener thread");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* let the parent decide how bad this really is */
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_os_thread_get(&listener_os_thread, ts->listener);
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* XXX under some circumstances not understood, children can get stuck
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in start_threads forever trying to take over slots which will
f4c310fd2555c6faca1f980f00b161eadb089023gstein * never be cleaned up; for now there is an APLOG_DEBUG message issued
f4c310fd2555c6faca1f980f00b161eadb089023gstein * every so often when this condition occurs
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We must create the fd queues before we start up the listener
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and worker threads. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_queue_init(worker_queue, ap_threads_per_child, pchild);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm "ap_queue_init() failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = ap_queue_info_create(&worker_queue_info, pchild,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ap_queue_info_create() failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein worker_sockets = apr_pcalloc(pchild, ap_threads_per_child
f4c310fd2555c6faca1f980f00b161eadb089023gstein * sizeof(apr_socket_t *));
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ap_threads_per_child does not include the listener thread */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < ap_threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->servers[child_num_arg][i].status;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "malloc: out of memory");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We are creating threads right now */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We let each thread update its own scoreboard entry. This is
f4c310fd2555c6faca1f980f00b161eadb089023gstein * done because it lets us deal with tid better.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_thread_create: unable to create worker thread");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* let the parent decide how bad this really is */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Start the listener only when there are workers available */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (start_thread_may_exit || threads_created == ap_threads_per_child) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* wait for previous generation to clean up an entry */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (loops % 120 == 0) { /* every couple of minutes */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "slots very quickly (%d of %d)",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* What state should this child_main process be listed as in the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * scoreboard...?
f4c310fd2555c6faca1f980f00b161eadb089023gstein * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * (request_rec *) NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This state should be listed separately in the scoreboard, in some kind
f4c310fd2555c6faca1f980f00b161eadb089023gstein * of process_status, not mixed in with the worker threads' status.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * "life_status" is almost right, but it's in the worker's structure, and
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * the name could be clearer. gla
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void join_workers(apr_thread_t * listener, apr_thread_t ** threads)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* deal with a rare timing window which affects waking up the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener thread... if the signal sent to the listener thread
f4c310fd2555c6faca1f980f00b161eadb089023gstein * is delivered between the time it verifies that the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * listener_may_exit flag is clear and the time it enters a
f4c310fd2555c6faca1f980f00b161eadb089023gstein * blocking syscall, the signal didn't do any good... work around
f4c310fd2555c6faca1f980f00b161eadb089023gstein * that by sleeping briefly and sending it again
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* listener not dead yet */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "the listener thread didn't exit");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_thread_join: unable to join listener thread");
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < ap_threads_per_child; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (threads[i]) { /* if we ever created this thread */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm "apr_thread_join: unable to join worker "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "thread %d", i);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void join_start_thread(apr_thread_t * start_thread_id)
f4c310fd2555c6faca1f980f00b161eadb089023gstein start_thread_may_exit = 1; /* tell it to give up in case it is still
f4c310fd2555c6faca1f980f00b161eadb089023gstein * trying to take over slots from a
f4c310fd2555c6faca1f980f00b161eadb089023gstein * previous generation
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_thread_join: unable to join the start " "thread");
f4c310fd2555c6faca1f980f00b161eadb089023gstein mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * child initializes
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*stuff to do before we switch id's, so we have permissions. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* done with init critical section */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Just use the standard apr_setup_signal_thread to block all signals
f4c310fd2555c6faca1f980f00b161eadb089023gstein * from being received. The child processes no longer use signals for
f4c310fd2555c6faca1f980f00b161eadb089023gstein * any communication with the parent process.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Couldn't initialize signal thread");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* coding a value of zero means infinity */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Setup worker threads */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* clear the storage; we may not create all our threads immediately,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and we want a 0 entry to indicate a thread which was not created
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "malloc: out of memory");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ts = (thread_starter *) apr_palloc(pchild, sizeof(*ts));
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* 0 means PTHREAD_CREATE_JOINABLE */
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein apr_threadattr_stacksize_set(thread_attr, ap_thread_stacksize);
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein rv = apr_thread_create(&start_thread_id, thread_attr, start_threads,
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_thread_create: unable to create worker thread");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* let the parent decide how bad this really is */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If we are only running in one_process mode, we will want to
f4c310fd2555c6faca1f980f00b161eadb089023gstein * still handle signals. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Block until we get a terminating signal. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* make sure the start thread has finished; signal_threads()
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and join_workers() depend on that
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX join_start_thread() won't be awakened if one of our
f4c310fd2555c6faca1f980f00b161eadb089023gstein * threads encounters a critical error and attempts to
f4c310fd2555c6faca1f980f00b161eadb089023gstein * shutdown this child
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* helps us terminate a little more quickly than the dispatch of the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * signal thread; beats the Pipe of Death and the browsers
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* A terminating signal was received. Now join each of the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * workers to clean them up.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If the worker already exited, then the join frees
f4c310fd2555c6faca1f980f00b161eadb089023gstein * their resources and returns.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If the worker hasn't exited, then this blocks until
f4c310fd2555c6faca1f980f00b161eadb089023gstein * they have (then cleans up).
f4c310fd2555c6faca1f980f00b161eadb089023gstein else { /* !one_process */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* remove SIGTERM from the set of blocked signals... if one of
f4c310fd2555c6faca1f980f00b161eadb089023gstein * the other threads in the process needs to take us down
f4c310fd2555c6faca1f980f00b161eadb089023gstein * (e.g., for MaxRequestsPerChild) it will send us SIGTERM
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Watch for any messages from the parent over the POD */
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* see if termination was triggered while we slept */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* make sure the start thread has finished;
f4c310fd2555c6faca1f980f00b161eadb089023gstein * signal_threads() and join_workers depend on that
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* A terminating signal was received. Now join each of the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * workers to clean them up.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If the worker already exited, then the join frees
f4c310fd2555c6faca1f980f00b161eadb089023gstein * their resources and returns.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If the worker hasn't exited, then this blocks until
f4c310fd2555c6faca1f980f00b161eadb089023gstein * they have (then cleans up).
f4c310fd2555c6faca1f980f00b161eadb089023gstein clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein "fork: Unable to fork new process");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* fork didn't succeed. Fix the scoreboard or else
f4c310fd2555c6faca1f980f00b161eadb089023gstein * it will say SERVER_STARTING forever and ever
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* In case system resources are maxxed out, we don't want
f4c310fd2555c6faca1f980f00b161eadb089023gstein Apache running away with the CPU trying to fork over and
f4c310fd2555c6faca1f980f00b161eadb089023gstein over and over again. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* By default, AIX binds to a single processor. This bit unbinds
f4c310fd2555c6faca1f980f00b161eadb089023gstein * children which will then bind to another CPU.
f4c310fd2555c6faca1f980f00b161eadb089023gstein int status = bindprocessor(BINDPROCESS, (int) getpid(),
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* start up a bunch of children */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein * idle_spawn_rate is the number of children that will be spawned on the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * next maintenance cycle if there aren't enough idle servers. It is
f4c310fd2555c6faca1f980f00b161eadb089023gstein * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
f4c310fd2555c6faca1f980f00b161eadb089023gstein * without the need to spawn.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* initialize the free_list */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < ap_daemons_limit; ++i) {
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein /* Initialization to satisfy the compiler. It doesn't know
f4c310fd2555c6faca1f980f00b161eadb089023gstein * that ap_threads_per_child is always > 0 */
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein for (j = 0; j < ap_threads_per_child; j++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX any_dying_threads is probably no longer needed GLA */
f4c310fd2555c6faca1f980f00b161eadb089023gstein any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
f4c310fd2555c6faca1f980f00b161eadb089023gstein (status == SERVER_DEAD || status == SERVER_GRACEFUL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We consider a starting server as idle because we started it
f4c310fd2555c6faca1f980f00b161eadb089023gstein * at least a cycle ago, and if it still hasn't finished starting
f4c310fd2555c6faca1f980f00b161eadb089023gstein * then we're just going to swamp things worse by forking more.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * So we hopefully won't need to fork more if we count it.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This depends on the ordering of SERVER_READY and SERVER_STARTING.
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ps->pid != 0) { /* XXX just set all_dead_threads in outer
f4c310fd2555c6faca1f980f00b161eadb089023gstein for loop if no pid? not much else matters */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (status <= SERVER_READY && status != SERVER_DEAD &&
f4c310fd2555c6faca1f980f00b161eadb089023gstein !ps->quiescing && ps->generation == ap_my_generation) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (status >= SERVER_READY && status < SERVER_GRACEFUL) {
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein || ps->quiescing)) { /* or at least one is going away */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* great! we prefer these, because the new process can
f4c310fd2555c6faca1f980f00b161eadb089023gstein * start more threads sooner. So prioritize this slot
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein * by putting it ahead of any slots with active threads.
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein * first, make room by moving a slot that's potentially still
f4c310fd2555c6faca1f980f00b161eadb089023gstein * in use to the end of the array
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein free_slots[free_length] = free_slots[totally_free_length];
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* slot is still in use - back of the bus
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX if (!ps->quiescing) is probably more reliable GLA */
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein /* some child processes appear to be working. don't kill the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * whole server.
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein /* looks like a basket case. give up.
f4c310fd2555c6faca1f980f00b161eadb089023gstein "No active workers found..."
f4c310fd2555c6faca1f980f00b161eadb089023gstein " Apache is exiting!");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* the child already logged the failure details */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Kill off one child */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* terminate the free list */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* only report this condition once */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm static int reported = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein "server reached MaxClients setting, consider"
f4c310fd2555c6faca1f980f00b161eadb089023gstein " raising the MaxClients setting");
f4c310fd2555c6faca1f980f00b161eadb089023gstein "server seems busy, (you may need "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "to increase StartServers, ThreadsPerChild "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "spawning %d children, there are around %d idle "
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < free_length; ++i) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* the next time around we want to spawn twice as many if this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * wasn't good enough, but not if we've just done a graceful
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void server_main_loop(int remaining_children_to_start)
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein processed_status = ap_process_child_status(&pid, exitwhy, status);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* tell perform_idle_server_maintenance to check into this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * on the next timer pop
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* non-fatal death... note that it's gone in the scoreboard. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < ap_threads_per_child; i++)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->parent[child_slot].quiescing = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* resource shortage, minimize the fork rate */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we're still doing a 1-for-1 replacement of dead
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * children with new children
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein /* handled */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Great, we've probably just lost a slot in the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * scoreboard. Somehow we don't know about this child.
f4c310fd2555c6faca1f980f00b161eadb089023gstein "long lost child came home! (pid %ld)",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Don't perform idle maintenance when a child dies,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * only do it when there's a timeout. Remember only a
f4c310fd2555c6faca1f980f00b161eadb089023gstein * finite number of children can die, and it's pretty
f4c310fd2555c6faca1f980f00b161eadb089023gstein * pathological for a lot to die suddenly.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* we hit a 1 second timeout in which none of the previous
f4c310fd2555c6faca1f980f00b161eadb089023gstein * generation of children needed to be reaped... so assume
f4c310fd2555c6faca1f980f00b161eadb089023gstein * they're all done, and pick up the slack if any is left.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* In any event we really shouldn't do the code below because
f4c310fd2555c6faca1f980f00b161eadb089023gstein * few of the servers we just started are in the IDLE state
f4c310fd2555c6faca1f980f00b161eadb089023gstein * yet, so we'd mistakenly create an extra server.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinint ap_mpm_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s)
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: Attempt to change ServerLimit or ThreadLimit "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "ignored during restart");
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* fix the generation number in the global score; we just got a new,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * cleared scoreboard
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->global->running_generation = ap_my_generation;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Don't thrash... */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (max_spare_threads < min_spare_threads + ap_threads_per_child)
f4c310fd2555c6faca1f980f00b161eadb089023gstein max_spare_threads = min_spare_threads + ap_threads_per_child;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If we're doing a graceful_restart then we're going to see a lot
f4c310fd2555c6faca1f980f00b161eadb089023gstein * of children exiting immediately when we get into the main loop
f4c310fd2555c6faca1f980f00b161eadb089023gstein * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty
f4c310fd2555c6faca1f980f00b161eadb089023gstein * rapidly... and for each one that exits we'll start a new one until
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we reach at least daemons_min_free. But we may be permitted to
f4c310fd2555c6faca1f980f00b161eadb089023gstein * start more than that, so we'll just keep track of how many we're
f4c310fd2555c6faca1f980f00b161eadb089023gstein * supposed to start up without the 1 second penalty between each fork.
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (remaining_children_to_start > ap_daemons_limit) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* give the system some time to recover before kicking into
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein * exponential mode */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "%s configured -- resuming normal operations",
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Time to shut down:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Kill child processes, tell them to call child_exit, etc...
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_reclaim_child_processes(1); /* Start with SIGTERM */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* cleanup pid file on normal shutdown */
f4c310fd2555c6faca1f980f00b161eadb089023gstein pidfile = ap_server_root_relative(pconf, ap_pid_fname);
f4c310fd2555c6faca1f980f00b161eadb089023gstein "removed PID file %s (pid=%ld)",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Time to gracefully shut down:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Kill child processes, tell them to call child_exit, etc...
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Close our listeners, and then ask our children to do same */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* cleanup pid file on normal shutdown */
f4c310fd2555c6faca1f980f00b161eadb089023gstein pidfile = ap_server_root_relative (pconf, ap_pid_fname);
f4c310fd2555c6faca1f980f00b161eadb089023gstein "removed PID file %s (pid=%ld)",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Don't really exit until each child has finished */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Pause for a second */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Relieve any children which have now exited */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Having just one child is enough to stay around */
f4c310fd2555c6faca1f980f00b161eadb089023gstein (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* We might be here because we received SIGTERM, either
f4c310fd2555c6faca1f980f00b161eadb089023gstein * way, try and make sure that all of our processes are
f4c310fd2555c6faca1f980f00b161eadb089023gstein * really dead.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we've been told to restart */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* not worth thinking about */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* advance to the next generation */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX: we really need to make sure this new generation number isn't in
f4c310fd2555c6faca1f980f00b161eadb089023gstein * use by any of the children.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_scoreboard_image->global->running_generation = ap_my_generation;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein " received. Doing graceful restart");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* wake up the children...time to die. But we'll have more soon */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* This is mostly for debugging... so that we know what is still
f4c310fd2555c6faca1f980f00b161eadb089023gstein * gracefully dealing with existing request.
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Kill 'em all. Since the child acts the same on the parents SIGTERM
f4c310fd2555c6faca1f980f00b161eadb089023gstein * and a SIGHUP, we may as well use the same signal, because some user
f4c310fd2555c6faca1f980f00b161eadb089023gstein * pthreads are stealing signals from us left and right.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_reclaim_child_processes(1); /* Start with SIGTERM */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "SIGHUP received. Attempting to restart");
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* This really should be a post_config hook, but the error log is already
f4c310fd2555c6faca1f980f00b161eadb089023gstein * redirected by that point, so we need to do this in the open_logs phase.
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int worker_open_logs(apr_pool_t * p, apr_pool_t * plog,
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_ALERT | APLOG_STARTUP, 0,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, "no listening sockets available, shutting down");
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_CRIT | APLOG_STARTUP, rv, NULL,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Could not open pipe-of-death.");
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int worker_pre_config(apr_pool_t * pconf, apr_pool_t * plog,
f4c310fd2555c6faca1f980f00b161eadb089023gstein static int restart_num = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* make sure that "ThreadsPerChild" gets set before "MaxClients" */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we're in the clear, got ThreadsPerChild first */
50bd75672ef114fb839dd9643c192b432fdf344cgstein /* now to swap the data */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Make sure you don't change 'next', or you may get loops! */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* XXX: first_child, parent, and data can never be set
f4c310fd2555c6faca1f980f00b161eadb089023gstein * for these directives, right? -aaron */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm && strncasecmp(pdir->directive, "MaxClients", 10) == 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein one_process = ap_exists_config_define("ONE_PROCESS");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* sigh, want this only the second time around */
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Couldn't create a Thread Safe Pollset. "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Is it supported on your platform?");
f4c310fd2555c6faca1f980f00b161eadb089023gstein rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
f4c310fd2555c6faca1f980f00b161eadb089023gstein "apr_proc_detach failed");
f4c310fd2555c6faca1f980f00b161eadb089023gstein min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
f4c310fd2555c6faca1f980f00b161eadb089023gstein max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* The worker open_logs phase must run before the core's, or stderr
f4c310fd2555c6faca1f980f00b161eadb089023gstein * will be redirected to a file, and the messages won't print to the
f4c310fd2555c6faca1f980f00b161eadb089023gstein static const char *const aszSucc[] = { "core.c", NULL };
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we need to set the MPM state before other pre-config hooks use MPM query
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to retrieve it, so register as REALLY_FIRST
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_min_spare_threads(cmd_parms * cmd, void *dummy,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: detected MinSpareThreads set to non-positive.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Resetting to 1 to avoid almost certain Apache failure.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Please read the documentation.");
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_max_spare_threads(cmd_parms * cmd, void *dummy,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_max_clients(cmd_parms * cmd, void *dummy,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* It is ok to use ap_threads_per_child here because we are
f4c310fd2555c6faca1f980f00b161eadb089023gstein * sure that it gets set before MaxClients in the pre_config stage. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: MaxClients (%d) must be at least as large",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " as ThreadsPerChild (%d). Automatically",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " increasing MaxClients to %d.", ap_threads_per_child);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_daemons_limit = max_clients / ap_threads_per_child;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((max_clients > 0) && (max_clients % ap_threads_per_child)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: MaxClients (%d) is not an integer multiple",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " of ThreadsPerChild (%d), lowering MaxClients to %d",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " for a maximum of %d child processes,",
f4c310fd2555c6faca1f980f00b161eadb089023gstein max_clients = ap_daemons_limit * ap_threads_per_child;
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: MaxClients of %d would require %d servers,",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " and would exceed the ServerLimit value of %d.",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " Automatically lowering MaxClients to %d. To increase,",
f4c310fd2555c6faca1f980f00b161eadb089023gstein " please see the ServerLimit directive.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: Require MaxClients > 0, setting to 1");
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_threads_per_child(cmd_parms * cmd, void *dummy,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "threads, lowering ThreadsPerChild to %d. To increase, "
f4c310fd2555c6faca1f980f00b161eadb089023gstein " ThreadLimit directive.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: Require ThreadsPerChild > 0, setting to 1");
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* you cannot change ServerLimit across a restart; ignore
f4c310fd2555c6faca1f980f00b161eadb089023gstein * any such attempts
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* how do we log a message? the error log is a bit bucket at this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * point; we'll just have to set a flag so that ap_mpm_run()
f4c310fd2555c6faca1f980f00b161eadb089023gstein * logs a warning later
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: ServerLimit of %d exceeds compile time limit "
4b28d4385b48010bc271cba9b40b56e458cbd5d8keith "WARNING: Require ServerLimit > 0, setting to 1");
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *set_thread_limit(cmd_parms * cmd, void *dummy,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *arg)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* you cannot change ThreadLimit across a restart; ignore
f4c310fd2555c6faca1f980f00b161eadb089023gstein * any such attempts
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (first_thread_limit && tmp_thread_limit != thread_limit) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* how do we log a message? the error log is a bit bucket at this
f4c310fd2555c6faca1f980f00b161eadb089023gstein * point; we'll just have to set a flag so that ap_mpm_run()
f4c310fd2555c6faca1f980f00b161eadb089023gstein * logs a warning later
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: ThreadLimit of %d exceeds compile time limit "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "WARNING: Require ThreadLimit > 0, setting to 1");
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Number of child processes launched at server startup"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Maximum number of child processes for this run of Apache"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Minimum number of idle threads, to handle request spikes"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Maximum number of idle threads"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Maximum number of threads alive at the same time"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Number of threads each child creates"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Maximum number of worker threads per child process for this "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "run of Apache - Upper limit for ThreadsPerChild"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_mpm_rewrite_args, /* hook to run before apache parses args */