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.
17
/* The purpose of this MPM is to fix the design flaws in the threaded
18
* model. Because of the way that pthreads and mutex locks interact,
19
* it is basically impossible to cleanly gracefully shutdown a child
20
* process if multiple threads are all blocked in accept. This model
21
* fixes those problems.
25
#include "apr_portable.h"
26
#include "apr_strings.h"
27
#include "apr_file_io.h"
28
#include "apr_thread_proc.h"
29
#include "apr_signal.h"
30
#include "apr_thread_mutex.h"
31
#include "apr_proc_mutex.h"
33
#define APR_WANT_STRFUNC
39
#if APR_HAVE_SYS_SOCKET_H
40
#include <sys/socket.h>
42
#if APR_HAVE_SYS_WAIT_H
45
#ifdef HAVE_SYS_PROCESSOR_H
46
#include <sys/processor.h> /* for bindprocessor() */
50
#error The Worker MPM requires APR threads, but they are unavailable.
55
#include "ap_config.h"
57
#include "http_main.h"
59
#include "http_config.h" /* for read_config */
60
#include "http_core.h" /* for get_remote_host */
61
#include "http_connection.h"
64
#include "mpm_common.h"
65
#include "ap_listen.h"
66
#include "scoreboard.h"
68
#include "mpm_default.h"
71
#include <limits.h> /* for INT_MAX */
73
/* Limit on the total --- clients will be locked out if more servers than
74
* this are needed. It is intended solely to keep the server from crashing
75
* when things get out of hand.
77
* We keep a hard maximum number of servers, for two reasons --- first off,
78
* in case something goes seriously wrong, we want to stop the fork bomb
79
* short of actually crashing the machine we're running on by filling some
80
* kernel table. Secondly, it keeps the size of the scoreboard file small
81
* enough that we can read the whole thing without worrying too much about
84
#ifndef DEFAULT_SERVER_LIMIT
85
#define DEFAULT_SERVER_LIMIT 16
88
/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
89
* some sort of compile-time limit to help catch typos.
91
#ifndef MAX_SERVER_LIMIT
92
#define MAX_SERVER_LIMIT 20000
95
/* Limit on the threads per process. Clients will be locked out if more than
96
* this * server_limit are needed.
98
* We keep this for one reason it keeps the size of the scoreboard file small
99
* enough that we can read the whole thing without worrying too much about
102
#ifndef DEFAULT_THREAD_LIMIT
103
#define DEFAULT_THREAD_LIMIT 64
106
/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
107
* some sort of compile-time limit to help catch typos.
109
#ifndef MAX_THREAD_LIMIT
110
#define MAX_THREAD_LIMIT 20000
114
* Actual definitions of config globals
117
int ap_threads_per_child = 0; /* Worker threads per child */
118
static int ap_daemons_to_start = 0;
119
static int min_spare_threads = 0;
120
static int max_spare_threads = 0;
121
static int ap_daemons_limit = 0;
122
static int server_limit = DEFAULT_SERVER_LIMIT;
123
static int first_server_limit = 0;
124
static int thread_limit = DEFAULT_THREAD_LIMIT;
125
static int first_thread_limit = 0;
126
static int changed_limit_at_restart;
127
static int dying = 0;
128
static int workers_may_exit = 0;
129
static int start_thread_may_exit = 0;
130
static int listener_may_exit = 0;
131
static int requests_this_child;
132
static int num_listensocks = 0;
133
static int resource_shortage = 0;
134
static fd_queue_t *worker_queue;
135
static fd_queue_info_t *worker_queue_info;
136
static int mpm_state = AP_MPMQ_STARTING;
137
static int sick_child_detected;
139
/* The structure used to pass unique initialization info to each thread */
146
/* Structure used to pass information to the thread responsible for
147
* creating the rest of the threads.
150
apr_thread_t **threads;
151
apr_thread_t *listener;
153
apr_threadattr_t *threadattr;
156
#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
159
* The max child slot ever assigned, preserved across restarts. Necessary
160
* to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
161
* use this value to optimize routines that have to scan the entire
164
int ap_max_daemons_limit = -1;
166
static ap_pod_t *pod;
168
/* *Non*-shared http_main globals... */
170
server_rec *ap_server_conf;
172
/* The worker MPM respects a couple of runtime flags that can aid
173
* in debugging. Setting the -DNO_DETACH flag will prevent the root process
174
* from detaching from its controlling terminal. Additionally, setting
175
* the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
176
* child_main loop running in the process which originally started up.
177
* This gives you a pretty nice debugging environment. (You'll get a SIGHUP
178
* early in standalone_main; just continue through. This is the server
179
* trying to kill off any child processes which it might have lying
180
* around --- Apache doesn't keep track of their pids, it just sends
181
* SIGHUP to the process group, ignoring it in the root process.
182
* Continue through and you'll be fine.).
185
static int one_process = 0;
188
int raise_sigstop_flags;
191
static apr_pool_t *pconf; /* Pool for config stuff */
192
static apr_pool_t *pchild; /* Pool for httpd child stuff */
194
static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
195
thread. Use this instead */
196
static pid_t parent_pid;
197
static apr_os_thread_t *listener_os_thread;
199
/* Locks for accept serialization */
200
static apr_proc_mutex_t *accept_mutex;
202
#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
203
#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)
205
#define SAFE_ACCEPT(stmt) (stmt)
208
/* The LISTENER_SIGNAL signal will be sent from the main thread to the
209
* listener thread to wake it up for graceful termination (what a child
210
* process from an old generation does when the admin does "apachectl
211
* graceful"). This signal will be blocked in all threads of a child
212
* process except for the listener thread.
214
#define LISTENER_SIGNAL SIGHUP
216
/* The WORKER_SIGNAL signal will be sent from the main thread to the
217
* worker threads during an ungraceful restart or shutdown.
218
* This ensures that on systems (i.e., Linux) where closing the worker
219
* socket doesn't awake the worker thread when it is polling on the socket
220
* (especially in apr_wait_for_io_or_timeout() when handling
221
* Keep-Alive connections), close_worker_sockets() and join_workers()
222
* still function in timely manner and allow ungraceful shutdowns to
223
* proceed to completion. Otherwise join_workers() doesn't return
224
* before the main process decides the child process is non-responsive
225
* and sends a SIGKILL.
227
#define WORKER_SIGNAL AP_SIG_GRACEFUL
229
/* An array of socket descriptors in use by each thread used to
230
* perform a non-graceful (forced) shutdown of the server. */
231
static apr_socket_t **worker_sockets;
233
static void close_worker_sockets(void)
236
for (i = 0; i < ap_threads_per_child; i++) {
237
if (worker_sockets[i]) {
238
apr_socket_close(worker_sockets[i]);
239
worker_sockets[i] = NULL;
244
static void wakeup_listener(void)
246
listener_may_exit = 1;
247
if (!listener_os_thread) {
248
/* XXX there is an obscure path that this doesn't handle perfectly:
249
* right after listener thread is created but before
250
* listener_os_thread is set, the first worker thread hits an
251
* error and starts graceful termination
256
* we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
257
* platforms and wake up the listener thread since it is the only thread
258
* with SIGHUP unblocked, but that doesn't work on Linux
260
#ifdef HAVE_PTHREAD_KILL
261
pthread_kill(*listener_os_thread, LISTENER_SIGNAL);
263
kill(ap_my_pid, LISTENER_SIGNAL);
268
#define ST_GRACEFUL 1
269
#define ST_UNGRACEFUL 2
271
static int terminate_mode = ST_INIT;
273
static void signal_threads(int mode)
275
if (terminate_mode == mode) {
278
terminate_mode = mode;
279
mpm_state = AP_MPMQ_STOPPING;
281
/* in case we weren't called from the listener thread, wake up the
286
/* for ungraceful termination, let the workers exit now;
287
* for graceful termination, the listener thread will notify the
288
* workers to exit once it has stopped accepting new connections
290
if (mode == ST_UNGRACEFUL) {
291
workers_may_exit = 1;
292
ap_queue_interrupt_all(worker_queue);
293
ap_queue_info_term(worker_queue_info);
294
close_worker_sockets(); /* forcefully kill all current connections */
298
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
301
case AP_MPMQ_MAX_DAEMON_USED:
302
*result = ap_max_daemons_limit;
304
case AP_MPMQ_IS_THREADED:
305
*result = AP_MPMQ_STATIC;
307
case AP_MPMQ_IS_FORKED:
308
*result = AP_MPMQ_DYNAMIC;
310
case AP_MPMQ_HARD_LIMIT_DAEMONS:
311
*result = server_limit;
313
case AP_MPMQ_HARD_LIMIT_THREADS:
314
*result = thread_limit;
316
case AP_MPMQ_MAX_THREADS:
317
*result = ap_threads_per_child;
319
case AP_MPMQ_MIN_SPARE_DAEMONS:
322
case AP_MPMQ_MIN_SPARE_THREADS:
323
*result = min_spare_threads;
325
case AP_MPMQ_MAX_SPARE_DAEMONS:
328
case AP_MPMQ_MAX_SPARE_THREADS:
329
*result = max_spare_threads;
331
case AP_MPMQ_MAX_REQUESTS_DAEMON:
332
*result = ap_max_requests_per_child;
334
case AP_MPMQ_MAX_DAEMONS:
335
*result = ap_daemons_limit;
337
case AP_MPMQ_MPM_STATE:
344
/* a clean exit from a child with proper cleanup */
345
static void clean_child_exit(int code) __attribute__ ((noreturn));
346
static void clean_child_exit(int code)
348
mpm_state = AP_MPMQ_STOPPING;
350
apr_pool_destroy(pchild);
355
static void just_die(int sig)
360
/*****************************************************************
361
* Connection structures and accounting...
364
/* volatile just in case */
365
static int volatile shutdown_pending;
366
static int volatile restart_pending;
367
static int volatile is_graceful;
368
static volatile int child_fatal;
369
ap_generation_t volatile ap_my_generation;
372
* ap_start_shutdown() and ap_start_restart(), below, are a first stab at
373
* functions to initiate shutdown or restart without relying on signals.
374
* Previously this was initiated in sig_term() and restart() signal handlers,
375
* but we want to be able to start a shutdown/restart from other sources --
376
* e.g. on Win32, from the service manager. Now the service manager can
377
* call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
378
* these functions can also be called by the child processes, since global
379
* variables are no longer used to pass on the required action to the parent.
381
* These should only be called from the parent process itself, since the
382
* parent process will use the shutdown_pending and restart_pending variables
383
* to determine whether to shutdown or restart. The child process should
384
* call signal_parent() directly to tell the parent to die -- this will
385
* cause neither of those variable to be set, which the parent will
386
* assume means something serious is wrong (which it will be, for the
387
* child to force an exit) and so do an exit anyway.
390
static void ap_start_shutdown(int graceful)
392
mpm_state = AP_MPMQ_STOPPING;
393
if (shutdown_pending == 1) {
394
/* Um, is this _probably_ not an error, if the user has
395
* tried to do a shutdown twice quickly, so we won't
396
* worry about reporting it.
400
shutdown_pending = 1;
401
is_graceful = graceful;
404
/* do a graceful restart if graceful == 1 */
405
static void ap_start_restart(int graceful)
407
mpm_state = AP_MPMQ_STOPPING;
408
if (restart_pending == 1) {
409
/* Probably not an error - don't bother reporting it */
413
is_graceful = graceful;
416
static void sig_term(int sig)
418
ap_start_shutdown(sig == AP_SIG_GRACEFUL_STOP);
421
static void restart(int sig)
423
ap_start_restart(sig == AP_SIG_GRACEFUL);
426
static void set_signals(void)
428
#ifndef NO_USE_SIGACTION
433
ap_fatal_signal_setup(ap_server_conf, pconf);
436
#ifndef NO_USE_SIGACTION
437
sigemptyset(&sa.sa_mask);
440
sa.sa_handler = sig_term;
441
if (sigaction(SIGTERM, &sa, NULL) < 0)
442
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
443
"sigaction(SIGTERM)");
444
#ifdef AP_SIG_GRACEFUL_STOP
445
if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
446
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
447
"sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
450
if (sigaction(SIGINT, &sa, NULL) < 0)
451
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
452
"sigaction(SIGINT)");
455
sa.sa_handler = SIG_DFL;
456
if (sigaction(SIGXCPU, &sa, NULL) < 0)
457
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
458
"sigaction(SIGXCPU)");
461
sa.sa_handler = SIG_DFL;
462
if (sigaction(SIGXFSZ, &sa, NULL) < 0)
463
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
464
"sigaction(SIGXFSZ)");
467
sa.sa_handler = SIG_IGN;
468
if (sigaction(SIGPIPE, &sa, NULL) < 0)
469
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
470
"sigaction(SIGPIPE)");
473
/* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
475
sigaddset(&sa.sa_mask, SIGHUP);
476
sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
477
sa.sa_handler = restart;
478
if (sigaction(SIGHUP, &sa, NULL) < 0)
479
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
480
"sigaction(SIGHUP)");
481
if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
482
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
483
"sigaction(" AP_SIG_GRACEFUL_STRING ")");
487
apr_signal(SIGXCPU, SIG_DFL);
490
apr_signal(SIGXFSZ, SIG_DFL);
494
apr_signal(SIGTERM, sig_term);
496
apr_signal(SIGHUP, restart);
498
#ifdef AP_SIG_GRACEFUL
499
apr_signal(AP_SIG_GRACEFUL, restart);
500
#endif /* AP_SIG_GRACEFUL */
501
#ifdef AP_SIG_GRACEFUL_STOP
502
apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
503
#endif /* AP_SIG_GRACEFUL_STOP */
505
apr_signal(SIGPIPE, SIG_IGN);
511
/*****************************************************************
512
* Here follows a long bunch of generic server bookkeeping stuff...
515
int ap_graceful_stop_signalled(void)
516
/* XXX this is really a bad confusing obsolete name
517
* maybe it should be ap_mpm_process_exiting?
520
/* note: for a graceful termination, listener_may_exit will be set before
521
* workers_may_exit, so check listener_may_exit
523
return listener_may_exit;
526
/*****************************************************************
527
* Child process main loop.
530
static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num,
531
int my_thread_num, apr_bucket_alloc_t *bucket_alloc)
533
conn_rec *current_conn;
534
long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
538
ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
539
apr_os_sock_get(&csd, sock);
541
current_conn = ap_run_create_connection(p, ap_server_conf, sock,
542
conn_id, sbh, bucket_alloc);
544
ap_process_connection(current_conn, sock);
545
ap_lingering_close(current_conn);
549
/* requests_this_child has gone to zero or below. See if the admin coded
550
"MaxRequestsPerChild 0", and keep going in that case. Doing it this way
551
simplifies the hot path in worker_thread */
552
static void check_infinite_requests(void)
554
if (ap_max_requests_per_child) {
555
signal_threads(ST_GRACEFUL);
558
/* wow! if you're executing this code, you may have set a record.
559
* either this child process has served over 2 billion requests, or
560
* you're running a threaded 2.0 on a 16 bit machine.
562
* I'll buy pizza and beers at Apachecon for the first person to do
563
* the former without cheating (dorking with INT_MAX, or running with
564
* uncommitted performance patches, for example).
566
* for the latter case, you probably deserve a beer too. Greg Ames
569
requests_this_child = INT_MAX; /* keep going */
573
static void unblock_signal(int sig)
577
sigemptyset(&sig_mask);
578
sigaddset(&sig_mask, sig);
579
#if defined(SIGPROCMASK_SETS_THREAD_MASK)
580
sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
582
pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL);
586
static void dummy_signal_handler(int sig)
588
/* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
589
* then we don't need this goofy function.
593
static void *listener_thread(apr_thread_t *thd, void * dummy)
595
proc_info * ti = dummy;
596
int process_slot = ti->pid;
597
apr_pool_t *tpool = apr_thread_pool_get(thd);
599
apr_pool_t *ptrans = NULL; /* Pool for per-transaction stuff */
600
apr_pollset_t *pollset;
603
int have_idle_worker = 0;
604
int last_poll_idx = 0;
608
/* ### check the status */
609
(void) apr_pollset_create(&pollset, num_listensocks, tpool, 0);
611
for (lr = ap_listeners; lr != NULL; lr = lr->next) {
612
apr_pollfd_t pfd = { 0 };
614
pfd.desc_type = APR_POLL_SOCKET;
616
pfd.reqevents = APR_POLLIN;
617
pfd.client_data = lr;
619
/* ### check the status */
620
(void) apr_pollset_add(pollset, &pfd);
623
/* Unblock the signal used to wake this thread up, and set a handler for
626
unblock_signal(LISTENER_SIGNAL);
627
apr_signal(LISTENER_SIGNAL, dummy_signal_handler);
629
/* TODO: Switch to a system where threads reuse the results from earlier
630
poll calls - manoj */
632
/* TODO: requests_this_child should be synchronized - aaron */
633
if (requests_this_child <= 0) {
634
check_infinite_requests();
636
if (listener_may_exit) break;
638
if (!have_idle_worker) {
639
/* the following pops a recycled ptrans pool off a stack
640
* if there is one, in addition to reserving a worker thread
642
rv = ap_queue_info_wait_for_idler(worker_queue_info,
644
if (APR_STATUS_IS_EOF(rv)) {
645
break; /* we've been signaled to die now */
647
else if (rv != APR_SUCCESS) {
648
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
649
"apr_queue_info_wait failed. Attempting to "
650
" shutdown process gracefully.");
651
signal_threads(ST_GRACEFUL);
654
have_idle_worker = 1;
657
/* We've already decremented the idle worker count inside
658
* ap_queue_info_wait_for_idler. */
660
if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(accept_mutex)))
662
int level = APLOG_EMERG;
664
if (listener_may_exit) {
667
if (ap_scoreboard_image->parent[process_slot].generation !=
668
ap_scoreboard_image->global->running_generation) {
669
level = APLOG_DEBUG; /* common to get these at restart time */
671
ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
672
"apr_proc_mutex_lock failed. Attempting to shutdown "
673
"process gracefully.");
674
signal_threads(ST_GRACEFUL);
675
break; /* skip the lock release */
678
if (!ap_listeners->next) {
679
/* Only one listener, so skip the poll */
683
while (!listener_may_exit) {
685
const apr_pollfd_t *pdesc;
687
rv = apr_pollset_poll(pollset, -1, &numdesc, &pdesc);
688
if (rv != APR_SUCCESS) {
689
if (APR_STATUS_IS_EINTR(rv)) {
693
/* apr_pollset_poll() will only return errors in catastrophic
694
* circumstances. Let's try exiting gracefully, for now. */
695
ap_log_error(APLOG_MARK, APLOG_ERR, rv,
696
(const server_rec *) ap_server_conf,
697
"apr_pollset_poll: (listen)");
698
signal_threads(ST_GRACEFUL);
701
if (listener_may_exit) break;
703
/* We can always use pdesc[0], but sockets at position N
704
* could end up completely starved of attention in a very
705
* busy server. Therefore, we round-robin across the
706
* returned set of descriptors. While it is possible that
707
* the returned set of descriptors might flip around and
708
* continue to starve some sockets, we happen to know the
709
* internal pollset implementation retains ordering
710
* stability of the sockets. Thus, the round-robin should
711
* ensure that a socket will eventually be serviced.
713
if (last_poll_idx >= numdesc)
716
/* Grab a listener record from the client_data of the poll
717
* descriptor, and advance our saved index to round-robin
720
* ### hmm... this descriptor might have POLLERR rather
723
lr = pdesc[last_poll_idx++].client_data;
730
if (!listener_may_exit) {
731
if (ptrans == NULL) {
732
/* we can't use a recycled transaction pool this time.
733
* create a new transaction pool */
734
apr_allocator_t *allocator;
736
apr_allocator_create(&allocator);
737
apr_allocator_max_free_set(allocator, ap_max_mem_free);
738
apr_pool_create_ex(&ptrans, pconf, NULL, allocator);
739
apr_allocator_owner_set(allocator, ptrans);
741
apr_pool_tag(ptrans, "transaction");
742
rv = lr->accept_func(&csd, lr, ptrans);
743
/* later we trash rv and rely on csd to indicate success/failure */
744
AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd);
746
if (rv == APR_EGENERAL) {
747
/* E[NM]FILE, ENOMEM, etc */
748
resource_shortage = 1;
749
signal_threads(ST_GRACEFUL);
751
if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex)))
753
int level = APLOG_EMERG;
755
if (listener_may_exit) {
758
if (ap_scoreboard_image->parent[process_slot].generation !=
759
ap_scoreboard_image->global->running_generation) {
760
level = APLOG_DEBUG; /* common to get these at restart time */
762
ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
763
"apr_proc_mutex_unlock failed. Attempting to "
764
"shutdown process gracefully.");
765
signal_threads(ST_GRACEFUL);
768
rv = ap_queue_push(worker_queue, csd, ptrans);
770
/* trash the connection; we couldn't queue the connected
773
apr_socket_close(csd);
774
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
775
"ap_queue_push failed");
778
have_idle_worker = 0;
783
if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex)))
785
int level = APLOG_EMERG;
787
if (ap_scoreboard_image->parent[process_slot].generation !=
788
ap_scoreboard_image->global->running_generation) {
789
level = APLOG_DEBUG; /* common to get these at restart time */
791
ap_log_error(APLOG_MARK, level, rv, ap_server_conf,
792
"apr_proc_mutex_unlock failed. Attempting to "
793
"shutdown process gracefully.");
794
signal_threads(ST_GRACEFUL);
800
ap_close_listeners();
801
ap_queue_term(worker_queue);
803
ap_scoreboard_image->parent[process_slot].quiescing = 1;
805
/* wake up the main thread */
806
kill(ap_my_pid, SIGTERM);
808
apr_thread_exit(thd, APR_SUCCESS);
812
/* XXX For ungraceful termination/restart, we definitely don't want to
813
* wait for active connections to finish but we may want to wait
814
* for idle workers to get out of the queue code and release mutexes,
815
* since those mutexes are cleaned up pretty soon and some systems
816
* may not react favorably (i.e., segfault) if operations are attempted
817
* on cleaned-up mutexes.
819
static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy)
821
proc_info * ti = dummy;
822
int process_slot = ti->pid;
823
int thread_slot = ti->tid;
824
apr_socket_t *csd = NULL;
825
apr_bucket_alloc_t *bucket_alloc;
826
apr_pool_t *last_ptrans = NULL;
827
apr_pool_t *ptrans; /* Pool for per-transaction stuff */
833
ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
834
ap_scoreboard_image->servers[process_slot][thread_slot].generation = ap_my_generation;
835
ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL);
837
#ifdef HAVE_PTHREAD_KILL
838
unblock_signal(WORKER_SIGNAL);
839
apr_signal(WORKER_SIGNAL, dummy_signal_handler);
842
while (!workers_may_exit) {
844
rv = ap_queue_info_set_idle(worker_queue_info, last_ptrans);
846
if (rv != APR_SUCCESS) {
847
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
848
"ap_queue_info_set_idle failed. Attempting to "
849
"shutdown process gracefully.");
850
signal_threads(ST_GRACEFUL);
856
ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL);
858
if (workers_may_exit) {
861
rv = ap_queue_pop(worker_queue, &csd, &ptrans);
863
if (rv != APR_SUCCESS) {
864
/* We get APR_EOF during a graceful shutdown once all the connections
865
* accepted by this server process have been handled.
867
if (APR_STATUS_IS_EOF(rv)) {
870
/* We get APR_EINTR whenever ap_queue_pop() has been interrupted
871
* from an explicit call to ap_queue_interrupt_all(). This allows
872
* us to unblock threads stuck in ap_queue_pop() when a shutdown
875
* If workers_may_exit is set and this is ungraceful termination/
876
* restart, we are bound to get an error on some systems (e.g.,
877
* AIX, which sanity-checks mutex operations) since the queue
878
* may have already been cleaned up. Don't log the "error" if
879
* workers_may_exit is set.
881
else if (APR_STATUS_IS_EINTR(rv)) {
884
/* We got some other error. */
885
else if (!workers_may_exit) {
886
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
887
"ap_queue_pop failed");
892
worker_sockets[thread_slot] = csd;
893
bucket_alloc = apr_bucket_alloc_create(ptrans);
894
process_socket(ptrans, csd, process_slot, thread_slot, bucket_alloc);
895
worker_sockets[thread_slot] = NULL;
896
requests_this_child--; /* FIXME: should be synchronized - aaron */
897
apr_pool_clear(ptrans);
898
last_ptrans = ptrans;
901
ap_update_child_status_from_indexes(process_slot, thread_slot,
902
(dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL);
904
apr_thread_exit(thd, APR_SUCCESS);
908
static int check_signal(int signum)
918
static void create_listener_thread(thread_starter *ts)
920
int my_child_num = ts->child_num_arg;
921
apr_threadattr_t *thread_attr = ts->threadattr;
925
my_info = (proc_info *)malloc(sizeof(proc_info));
926
my_info->pid = my_child_num;
927
my_info->tid = -1; /* listener thread doesn't have a thread slot */
929
rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,
931
if (rv != APR_SUCCESS) {
932
ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
933
"apr_thread_create: unable to create listener thread");
934
/* let the parent decide how bad this really is */
935
clean_child_exit(APEXIT_CHILDSICK);
937
apr_os_thread_get(&listener_os_thread, ts->listener);
940
/* XXX under some circumstances not understood, children can get stuck
941
* in start_threads forever trying to take over slots which will
942
* never be cleaned up; for now there is an APLOG_DEBUG message issued
943
* every so often when this condition occurs
945
static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy)
947
thread_starter *ts = dummy;
948
apr_thread_t **threads = ts->threads;
949
apr_threadattr_t *thread_attr = ts->threadattr;
950
int child_num_arg = ts->child_num_arg;
951
int my_child_num = child_num_arg;
955
int threads_created = 0;
956
int listener_started = 0;
958
int prev_threads_created;
960
/* We must create the fd queues before we start up the listener
961
* and worker threads. */
962
worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
963
rv = ap_queue_init(worker_queue, ap_threads_per_child, pchild);
964
if (rv != APR_SUCCESS) {
965
ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
966
"ap_queue_init() failed");
967
clean_child_exit(APEXIT_CHILDFATAL);
970
rv = ap_queue_info_create(&worker_queue_info, pchild,
971
ap_threads_per_child);
972
if (rv != APR_SUCCESS) {
973
ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
974
"ap_queue_info_create() failed");
975
clean_child_exit(APEXIT_CHILDFATAL);
978
worker_sockets = apr_pcalloc(pchild, ap_threads_per_child
979
* sizeof(apr_socket_t *));
981
loops = prev_threads_created = 0;
983
/* ap_threads_per_child does not include the listener thread */
984
for (i = 0; i < ap_threads_per_child; i++) {
985
int status = ap_scoreboard_image->servers[child_num_arg][i].status;
987
if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
991
my_info = (proc_info *)malloc(sizeof(proc_info));
992
if (my_info == NULL) {
993
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
994
"malloc: out of memory");
995
clean_child_exit(APEXIT_CHILDFATAL);
997
my_info->pid = my_child_num;
1001
/* We are creating threads right now */
1002
ap_update_child_status_from_indexes(my_child_num, i,
1003
SERVER_STARTING, NULL);
1004
/* We let each thread update its own scoreboard entry. This is
1005
* done because it lets us deal with tid better.
1007
rv = apr_thread_create(&threads[i], thread_attr,
1008
worker_thread, my_info, pchild);
1009
if (rv != APR_SUCCESS) {
1010
ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
1011
"apr_thread_create: unable to create worker thread");
1012
/* let the parent decide how bad this really is */
1013
clean_child_exit(APEXIT_CHILDSICK);
1017
/* Start the listener only when there are workers available */
1018
if (!listener_started && threads_created) {
1019
create_listener_thread(ts);
1020
listener_started = 1;
1022
if (start_thread_may_exit || threads_created == ap_threads_per_child) {
1025
/* wait for previous generation to clean up an entry */
1026
apr_sleep(apr_time_from_sec(1));
1028
if (loops % 120 == 0) { /* every couple of minutes */
1029
if (prev_threads_created == threads_created) {
1030
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1031
"child %" APR_PID_T_FMT " isn't taking over "
1032
"slots very quickly (%d of %d)",
1033
ap_my_pid, threads_created, ap_threads_per_child);
1035
prev_threads_created = threads_created;
1039
/* What state should this child_main process be listed as in the
1041
* ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
1042
* (request_rec *) NULL);
1044
* This state should be listed separately in the scoreboard, in some kind
1045
* of process_status, not mixed in with the worker threads' status.
1046
* "life_status" is almost right, but it's in the worker's structure, and
1047
* the name could be clearer. gla
1049
apr_thread_exit(thd, APR_SUCCESS);
1053
static void join_workers(apr_thread_t *listener, apr_thread_t **threads)
1056
apr_status_t rv, thread_rv;
1061
/* deal with a rare timing window which affects waking up the
1062
* listener thread... if the signal sent to the listener thread
1063
* is delivered between the time it verifies that the
1064
* listener_may_exit flag is clear and the time it enters a
1065
* blocking syscall, the signal didn't do any good... work around
1066
* that by sleeping briefly and sending it again
1071
#ifdef HAVE_PTHREAD_KILL
1072
pthread_kill(*listener_os_thread, 0)
1077
/* listener not dead yet */
1078
apr_sleep(apr_time_make(0, 500000));
1083
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1084
"the listener thread didn't exit");
1087
rv = apr_thread_join(&thread_rv, listener);
1088
if (rv != APR_SUCCESS) {
1089
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
1090
"apr_thread_join: unable to join listener thread");
1095
for (i = 0; i < ap_threads_per_child; i++) {
1096
if (threads[i]) { /* if we ever created this thread */
1097
#ifdef HAVE_PTHREAD_KILL
1098
apr_os_thread_t *worker_os_thread;
1100
apr_os_thread_get(&worker_os_thread, threads[i]);
1101
pthread_kill(*worker_os_thread, WORKER_SIGNAL);
1104
rv = apr_thread_join(&thread_rv, threads[i]);
1105
if (rv != APR_SUCCESS) {
1106
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
1107
"apr_thread_join: unable to join worker "
1115
static void join_start_thread(apr_thread_t *start_thread_id)
1117
apr_status_t rv, thread_rv;
1119
start_thread_may_exit = 1; /* tell it to give up in case it is still
1120
* trying to take over slots from a
1121
* previous generation
1123
rv = apr_thread_join(&thread_rv, start_thread_id);
1124
if (rv != APR_SUCCESS) {
1125
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
1126
"apr_thread_join: unable to join the start "
1131
static void child_main(int child_num_arg)
1133
apr_thread_t **threads;
1136
apr_threadattr_t *thread_attr;
1137
apr_thread_t *start_thread_id;
1139
mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
1142
ap_my_pid = getpid();
1143
ap_fatal_signal_child_setup(ap_server_conf);
1144
apr_pool_create(&pchild, pconf);
1146
/*stuff to do before we switch id's, so we have permissions.*/
1147
ap_reopen_scoreboard(pchild, NULL, 0);
1149
rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname,
1151
if (rv != APR_SUCCESS) {
1152
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
1153
"Couldn't initialize cross-process lock in child");
1154
clean_child_exit(APEXIT_CHILDFATAL);
1157
if (unixd_setup_child()) {
1158
clean_child_exit(APEXIT_CHILDFATAL);
1161
ap_run_child_init(pchild, ap_server_conf);
1163
/* done with init critical section */
1165
/* Just use the standard apr_setup_signal_thread to block all signals
1166
* from being received. The child processes no longer use signals for
1167
* any communication with the parent process.
1169
rv = apr_setup_signal_thread();
1170
if (rv != APR_SUCCESS) {
1171
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
1172
"Couldn't initialize signal thread");
1173
clean_child_exit(APEXIT_CHILDFATAL);
1176
if (ap_max_requests_per_child) {
1177
requests_this_child = ap_max_requests_per_child;
1180
/* coding a value of zero means infinity */
1181
requests_this_child = INT_MAX;
1184
/* Setup worker threads */
1186
/* clear the storage; we may not create all our threads immediately,
1187
* and we want a 0 entry to indicate a thread which was not created
1189
threads = (apr_thread_t **)calloc(1,
1190
sizeof(apr_thread_t *) * ap_threads_per_child);
1191
if (threads == NULL) {
1192
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
1193
"malloc: out of memory");
1194
clean_child_exit(APEXIT_CHILDFATAL);
1197
ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts));
1199
apr_threadattr_create(&thread_attr, pchild);
1200
/* 0 means PTHREAD_CREATE_JOINABLE */
1201
apr_threadattr_detach_set(thread_attr, 0);
1203
if (ap_thread_stacksize != 0) {
1204
apr_threadattr_stacksize_set(thread_attr, ap_thread_stacksize);
1207
ts->threads = threads;
1208
ts->listener = NULL;
1209
ts->child_num_arg = child_num_arg;
1210
ts->threadattr = thread_attr;
1212
rv = apr_thread_create(&start_thread_id, thread_attr, start_threads,
1214
if (rv != APR_SUCCESS) {
1215
ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
1216
"apr_thread_create: unable to create worker thread");
1217
/* let the parent decide how bad this really is */
1218
clean_child_exit(APEXIT_CHILDSICK);
1221
mpm_state = AP_MPMQ_RUNNING;
1223
/* If we are only running in one_process mode, we will want to
1224
* still handle signals. */
1226
/* Block until we get a terminating signal. */
1227
apr_signal_thread(check_signal);
1228
/* make sure the start thread has finished; signal_threads()
1229
* and join_workers() depend on that
1231
/* XXX join_start_thread() won't be awakened if one of our
1232
* threads encounters a critical error and attempts to
1233
* shutdown this child
1235
join_start_thread(start_thread_id);
1236
signal_threads(ST_UNGRACEFUL); /* helps us terminate a little more
1237
* quickly than the dispatch of the signal thread
1238
* beats the Pipe of Death and the browsers
1240
/* A terminating signal was received. Now join each of the
1241
* workers to clean them up.
1242
* If the worker already exited, then the join frees
1243
* their resources and returns.
1244
* If the worker hasn't exited, then this blocks until
1245
* they have (then cleans up).
1247
join_workers(ts->listener, threads);
1249
else { /* !one_process */
1250
/* remove SIGTERM from the set of blocked signals... if one of
1251
* the other threads in the process needs to take us down
1252
* (e.g., for MaxRequestsPerChild) it will send us SIGTERM
1254
unblock_signal(SIGTERM);
1255
apr_signal(SIGTERM, dummy_signal_handler);
1256
/* Watch for any messages from the parent over the POD */
1258
rv = ap_mpm_pod_check(pod);
1259
if (rv == AP_NORESTART) {
1260
/* see if termination was triggered while we slept */
1261
switch(terminate_mode) {
1270
if (rv == AP_GRACEFUL || rv == AP_RESTART) {
1271
/* make sure the start thread has finished;
1272
* signal_threads() and join_workers depend on that
1274
join_start_thread(start_thread_id);
1275
signal_threads(rv == AP_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL);
1280
/* A terminating signal was received. Now join each of the
1281
* workers to clean them up.
1282
* If the worker already exited, then the join frees
1283
* their resources and returns.
1284
* If the worker hasn't exited, then this blocks until
1285
* they have (then cleans up).
1287
join_workers(ts->listener, threads);
1292
clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);
1295
static int make_child(server_rec *s, int slot)
1299
if (slot + 1 > ap_max_daemons_limit) {
1300
ap_max_daemons_limit = slot + 1;
1305
ap_scoreboard_image->parent[slot].pid = getpid();
1309
if ((pid = fork()) == -1) {
1310
ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
1311
"fork: Unable to fork new process");
1313
/* fork didn't succeed. Fix the scoreboard or else
1314
* it will say SERVER_STARTING forever and ever
1316
ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL);
1318
/* In case system resources are maxxed out, we don't want
1319
Apache running away with the CPU trying to fork over and
1320
over and over again. */
1321
apr_sleep(apr_time_from_sec(10));
1327
#ifdef HAVE_BINDPROCESSOR
1328
/* By default, AIX binds to a single processor. This bit unbinds
1329
* children which will then bind to another CPU.
1331
int status = bindprocessor(BINDPROCESS, (int)getpid(),
1332
PROCESSOR_CLASS_ANY);
1334
ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
1336
"processor unbind failed %d", status);
1338
RAISE_SIGSTOP(MAKE_CHILD);
1340
apr_signal(SIGTERM, just_die);
1343
clean_child_exit(0);
1346
if (ap_scoreboard_image->parent[slot].pid != 0) {
1347
/* This new child process is squatting on the scoreboard
1348
* entry owned by an exiting child process, which cannot
1349
* exit until all active requests complete.
1350
* Don't forget about this exiting child process, or we
1351
* won't be able to kill it if it doesn't exit by the
1352
* time the server is shut down.
1354
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1355
"taking over scoreboard slot from %" APR_PID_T_FMT "%s",
1356
ap_scoreboard_image->parent[slot].pid,
1357
ap_scoreboard_image->parent[slot].quiescing ?
1358
" (quiescing)" : "");
1359
ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid);
1361
ap_scoreboard_image->parent[slot].quiescing = 0;
1362
ap_scoreboard_image->parent[slot].pid = pid;
1366
/* start up a bunch of children */
1367
static void startup_children(int number_to_start)
1371
for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
1372
if (ap_scoreboard_image->parent[i].pid != 0) {
1375
if (make_child(ap_server_conf, i) < 0) {
1384
* idle_spawn_rate is the number of children that will be spawned on the
1385
* next maintenance cycle if there aren't enough idle servers. It is
1386
* doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
1387
* without the need to spawn.
1389
static int idle_spawn_rate = 1;
1390
#ifndef MAX_SPAWN_RATE
1391
#define MAX_SPAWN_RATE (32)
1393
static int hold_off_on_exponential_spawning;
1395
static void perform_idle_server_maintenance(void)
1398
int idle_thread_count;
1402
int totally_free_length = 0;
1403
int free_slots[MAX_SPAWN_RATE];
1406
int active_thread_count = 0;
1408
/* initialize the free_list */
1411
idle_thread_count = 0;
1415
for (i = 0; i < ap_daemons_limit; ++i) {
1416
/* Initialization to satisfy the compiler. It doesn't know
1417
* that ap_threads_per_child is always > 0 */
1418
int status = SERVER_DEAD;
1419
int any_dying_threads = 0;
1420
int any_dead_threads = 0;
1421
int all_dead_threads = 1;
1423
if (i >= ap_max_daemons_limit && totally_free_length == idle_spawn_rate)
1425
ps = &ap_scoreboard_image->parent[i];
1426
for (j = 0; j < ap_threads_per_child; j++) {
1427
ws = &ap_scoreboard_image->servers[i][j];
1428
status = ws->status;
1430
/* XXX any_dying_threads is probably no longer needed GLA */
1431
any_dying_threads = any_dying_threads ||
1432
(status == SERVER_GRACEFUL);
1433
any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
1434
all_dead_threads = all_dead_threads &&
1435
(status == SERVER_DEAD ||
1436
status == SERVER_GRACEFUL);
1438
/* We consider a starting server as idle because we started it
1439
* at least a cycle ago, and if it still hasn't finished starting
1440
* then we're just going to swamp things worse by forking more.
1441
* So we hopefully won't need to fork more if we count it.
1442
* This depends on the ordering of SERVER_READY and SERVER_STARTING.
1444
if (ps->pid != 0) { /* XXX just set all_dead_threads in outer for
1445
loop if no pid? not much else matters */
1446
if (status <= SERVER_READY &&
1448
ps->generation == ap_my_generation) {
1449
++idle_thread_count;
1451
if (status >= SERVER_READY && status < SERVER_GRACEFUL) {
1452
++active_thread_count;
1456
if (any_dead_threads && totally_free_length < idle_spawn_rate
1457
&& free_length < MAX_SPAWN_RATE
1458
&& (!ps->pid /* no process in the slot */
1459
|| ps->quiescing)) { /* or at least one is going away */
1460
if (all_dead_threads) {
1461
/* great! we prefer these, because the new process can
1462
* start more threads sooner. So prioritize this slot
1463
* by putting it ahead of any slots with active threads.
1465
* first, make room by moving a slot that's potentially still
1466
* in use to the end of the array
1468
free_slots[free_length] = free_slots[totally_free_length];
1469
free_slots[totally_free_length++] = i;
1472
/* slot is still in use - back of the bus
1474
free_slots[free_length] = i;
1478
/* XXX if (!ps->quiescing) is probably more reliable GLA */
1479
if (!any_dying_threads) {
1485
if (sick_child_detected) {
1486
if (active_thread_count > 0) {
1487
/* some child processes appear to be working. don't kill the
1490
sick_child_detected = 0;
1493
/* looks like a basket case. give up.
1495
shutdown_pending = 1;
1497
ap_log_error(APLOG_MARK, APLOG_ALERT, 0,
1499
"No active workers found..."
1500
" Apache is exiting!");
1501
/* the child already logged the failure details */
1506
ap_max_daemons_limit = last_non_dead + 1;
1508
if (idle_thread_count > max_spare_threads) {
1509
/* Kill off one child */
1510
ap_mpm_pod_signal(pod, TRUE);
1511
idle_spawn_rate = 1;
1513
else if (idle_thread_count < min_spare_threads) {
1514
/* terminate the free list */
1515
if (free_length == 0) {
1516
/* only report this condition once */
1517
static int reported = 0;
1520
ap_log_error(APLOG_MARK, APLOG_ERR, 0,
1522
"server reached MaxClients setting, consider"
1523
" raising the MaxClients setting");
1526
idle_spawn_rate = 1;
1529
if (free_length > idle_spawn_rate) {
1530
free_length = idle_spawn_rate;
1532
if (idle_spawn_rate >= 8) {
1533
ap_log_error(APLOG_MARK, APLOG_INFO, 0,
1535
"server seems busy, (you may need "
1536
"to increase StartServers, ThreadsPerChild "
1537
"or Min/MaxSpareThreads), "
1538
"spawning %d children, there are around %d idle "
1539
"threads, and %d total children", free_length,
1540
idle_thread_count, total_non_dead);
1542
for (i = 0; i < free_length; ++i) {
1543
make_child(ap_server_conf, free_slots[i]);
1545
/* the next time around we want to spawn twice as many if this
1546
* wasn't good enough, but not if we've just done a graceful
1548
if (hold_off_on_exponential_spawning) {
1549
--hold_off_on_exponential_spawning;
1551
else if (idle_spawn_rate < MAX_SPAWN_RATE) {
1552
idle_spawn_rate *= 2;
1557
idle_spawn_rate = 1;
1561
static void server_main_loop(int remaining_children_to_start)
1564
apr_exit_why_e exitwhy;
1565
int status, processed_status;
1569
while (!restart_pending && !shutdown_pending) {
1570
ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
1572
if (pid.pid != -1) {
1573
processed_status = ap_process_child_status(&pid, exitwhy, status);
1574
if (processed_status == APEXIT_CHILDFATAL) {
1575
shutdown_pending = 1;
1579
else if (processed_status == APEXIT_CHILDSICK) {
1580
/* tell perform_idle_server_maintenance to check into this
1581
* on the next timer pop
1583
sick_child_detected = 1;
1585
/* non-fatal death... note that it's gone in the scoreboard. */
1586
child_slot = find_child_by_pid(&pid);
1587
if (child_slot >= 0) {
1588
for (i = 0; i < ap_threads_per_child; i++)
1589
ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
1590
(request_rec *) NULL);
1592
ap_scoreboard_image->parent[child_slot].pid = 0;
1593
ap_scoreboard_image->parent[child_slot].quiescing = 0;
1594
if (processed_status == APEXIT_CHILDSICK) {
1595
/* resource shortage, minimize the fork rate */
1596
idle_spawn_rate = 1;
1598
else if (remaining_children_to_start
1599
&& child_slot < ap_daemons_limit) {
1600
/* we're still doing a 1-for-1 replacement of dead
1601
* children with new children
1603
make_child(ap_server_conf, child_slot);
1604
--remaining_children_to_start;
1607
else if (ap_unregister_extra_mpm_process(pid.pid) == 1) {
1609
#if APR_HAS_OTHER_CHILD
1611
else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
1616
else if (is_graceful) {
1617
/* Great, we've probably just lost a slot in the
1618
* scoreboard. Somehow we don't know about this child.
1620
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
1622
"long lost child came home! (pid %ld)",
1625
/* Don't perform idle maintenance when a child dies,
1626
* only do it when there's a timeout. Remember only a
1627
* finite number of children can die, and it's pretty
1628
* pathological for a lot to die suddenly.
1632
else if (remaining_children_to_start) {
1633
/* we hit a 1 second timeout in which none of the previous
1634
* generation of children needed to be reaped... so assume
1635
* they're all done, and pick up the slack if any is left.
1637
startup_children(remaining_children_to_start);
1638
remaining_children_to_start = 0;
1639
/* In any event we really shouldn't do the code below because
1640
* few of the servers we just started are in the IDLE state
1641
* yet, so we'd mistakenly create an extra server.
1646
perform_idle_server_maintenance();
1650
int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
1652
int remaining_children_to_start;
1655
ap_log_pid(pconf, ap_pid_fname);
1657
first_server_limit = server_limit;
1658
first_thread_limit = thread_limit;
1659
if (changed_limit_at_restart) {
1660
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1661
"WARNING: Attempt to change ServerLimit or ThreadLimit "
1662
"ignored during restart");
1663
changed_limit_at_restart = 0;
1666
/* Initialize cross-process accept lock */
1667
ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT,
1668
ap_server_root_relative(_pconf, ap_lock_fname),
1671
rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,
1672
ap_accept_lock_mech, _pconf);
1673
if (rv != APR_SUCCESS) {
1674
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
1675
"Couldn't create accept lock");
1676
mpm_state = AP_MPMQ_STOPPING;
1680
#if APR_USE_SYSVSEM_SERIALIZE
1681
if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
1682
ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
1684
if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
1686
rv = unixd_set_proc_mutex_perms(accept_mutex);
1687
if (rv != APR_SUCCESS) {
1688
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
1689
"Couldn't set permissions on cross-process lock; "
1690
"check User and Group directives");
1691
mpm_state = AP_MPMQ_STOPPING;
1697
if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
1698
mpm_state = AP_MPMQ_STOPPING;
1701
/* fix the generation number in the global score; we just got a new,
1702
* cleared scoreboard
1704
ap_scoreboard_image->global->running_generation = ap_my_generation;
1708
/* Don't thrash... */
1709
if (max_spare_threads < min_spare_threads + ap_threads_per_child)
1710
max_spare_threads = min_spare_threads + ap_threads_per_child;
1712
/* If we're doing a graceful_restart then we're going to see a lot
1713
* of children exiting immediately when we get into the main loop
1714
* below (because we just sent them AP_SIG_GRACEFUL). This happens pretty
1715
* rapidly... and for each one that exits we'll start a new one until
1716
* we reach at least daemons_min_free. But we may be permitted to
1717
* start more than that, so we'll just keep track of how many we're
1718
* supposed to start up without the 1 second penalty between each fork.
1720
remaining_children_to_start = ap_daemons_to_start;
1721
if (remaining_children_to_start > ap_daemons_limit) {
1722
remaining_children_to_start = ap_daemons_limit;
1725
startup_children(remaining_children_to_start);
1726
remaining_children_to_start = 0;
1729
/* give the system some time to recover before kicking into
1730
* exponential mode */
1731
hold_off_on_exponential_spawning = 10;
1734
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1735
"%s configured -- resuming normal operations",
1736
ap_get_server_version());
1737
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
1738
"Server built: %s", ap_get_server_built());
1739
#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
1740
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1741
"AcceptMutex: %s (default: %s)",
1742
apr_proc_mutex_name(accept_mutex),
1743
apr_proc_mutex_defname());
1745
restart_pending = shutdown_pending = 0;
1746
mpm_state = AP_MPMQ_RUNNING;
1748
server_main_loop(remaining_children_to_start);
1749
mpm_state = AP_MPMQ_STOPPING;
1751
if (shutdown_pending && !is_graceful) {
1752
/* Time to shut down:
1753
* Kill child processes, tell them to call child_exit, etc...
1755
ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
1756
ap_reclaim_child_processes(1); /* Start with SIGTERM */
1759
/* cleanup pid file on normal shutdown */
1760
const char *pidfile = NULL;
1761
pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1762
if ( pidfile != NULL && unlink(pidfile) == 0)
1763
ap_log_error(APLOG_MARK, APLOG_INFO, 0,
1765
"removed PID file %s (pid=%" APR_PID_T_FMT ")",
1768
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1769
ap_server_conf, "caught SIGTERM, shutting down");
1772
} else if (shutdown_pending) {
1773
/* Time to gracefully shut down:
1774
* Kill child processes, tell them to call child_exit, etc...
1776
int active_children;
1778
apr_time_t cutoff = 0;
1780
/* Close our listeners, and then ask our children to do same */
1781
ap_close_listeners();
1782
ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE);
1783
ap_relieve_child_processes();
1786
/* cleanup pid file on normal shutdown */
1787
const char *pidfile = NULL;
1788
pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1789
if ( pidfile != NULL && unlink(pidfile) == 0)
1790
ap_log_error(APLOG_MARK, APLOG_INFO, 0,
1792
"removed PID file %s (pid=%" APR_PID_T_FMT ")",
1795
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1796
"caught " AP_SIG_GRACEFUL_STOP_STRING
1797
", shutting down gracefully");
1800
if (ap_graceful_shutdown_timeout) {
1801
cutoff = apr_time_now() +
1802
apr_time_from_sec(ap_graceful_shutdown_timeout);
1805
/* Don't really exit until each child has finished */
1806
shutdown_pending = 0;
1808
/* Pause for a second */
1809
apr_sleep(apr_time_from_sec(1));
1811
/* Relieve any children which have now exited */
1812
ap_relieve_child_processes();
1814
active_children = 0;
1815
for (index = 0; index < ap_daemons_limit; ++index) {
1816
if (MPM_CHILD_PID(index) != 0) {
1817
if (kill(MPM_CHILD_PID(index), 0) == 0) {
1818
active_children = 1;
1819
/* Having just one child is enough to stay around */
1824
} while (!shutdown_pending && active_children &&
1825
(!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
1827
/* We might be here because we received SIGTERM, either
1828
* way, try and make sure that all of our processes are
1831
ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
1832
ap_reclaim_child_processes(1);
1837
/* we've been told to restart */
1838
apr_signal(SIGHUP, SIG_IGN);
1841
/* not worth thinking about */
1845
/* advance to the next generation */
1846
/* XXX: we really need to make sure this new generation number isn't in
1847
* use by any of the children.
1850
ap_scoreboard_image->global->running_generation = ap_my_generation;
1853
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1854
AP_SIG_GRACEFUL_STRING " received. Doing graceful restart");
1855
/* wake up the children...time to die. But we'll have more soon */
1856
ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE);
1859
/* This is mostly for debugging... so that we know what is still
1860
* gracefully dealing with existing request.
1865
/* Kill 'em all. Since the child acts the same on the parents SIGTERM
1866
* and a SIGHUP, we may as well use the same signal, because some user
1867
* pthreads are stealing signals from us left and right.
1869
ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
1871
ap_reclaim_child_processes(1); /* Start with SIGTERM */
1872
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1873
"SIGHUP received. Attempting to restart");
1879
/* This really should be a post_config hook, but the error log is already
1880
* redirected by that point, so we need to do this in the open_logs phase.
1882
static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
1889
if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
1890
ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
1891
NULL, "no listening sockets available, shutting down");
1896
if ((rv = ap_mpm_pod_open(pconf, &pod))) {
1897
ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
1898
"Could not open pipe-of-death.");
1905
static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
1908
static int restart_num = 0;
1909
int no_detach, debug, foreground;
1910
ap_directive_t *pdir;
1911
ap_directive_t *max_clients = NULL;
1914
mpm_state = AP_MPMQ_STARTING;
1916
/* make sure that "ThreadsPerChild" gets set before "MaxClients" */
1917
for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) {
1918
if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) {
1920
break; /* we're in the clear, got ThreadsPerChild first */
1923
/* now to swap the data */
1924
ap_directive_t temp;
1926
temp.directive = pdir->directive;
1927
temp.args = pdir->args;
1928
/* Make sure you don't change 'next', or you may get loops! */
1929
/* XXX: first_child, parent, and data can never be set
1930
* for these directives, right? -aaron */
1931
temp.filename = pdir->filename;
1932
temp.line_num = pdir->line_num;
1934
pdir->directive = max_clients->directive;
1935
pdir->args = max_clients->args;
1936
pdir->filename = max_clients->filename;
1937
pdir->line_num = max_clients->line_num;
1939
max_clients->directive = temp.directive;
1940
max_clients->args = temp.args;
1941
max_clients->filename = temp.filename;
1942
max_clients->line_num = temp.line_num;
1946
else if (!max_clients
1947
&& strncasecmp(pdir->directive, "MaxClients", 10) == 0) {
1952
debug = ap_exists_config_define("DEBUG");
1955
foreground = one_process = 1;
1959
one_process = ap_exists_config_define("ONE_PROCESS");
1960
no_detach = ap_exists_config_define("NO_DETACH");
1961
foreground = ap_exists_config_define("FOREGROUND");
1964
/* sigh, want this only the second time around */
1965
if (restart_num++ == 1) {
1968
if (!one_process && !foreground) {
1969
rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
1970
: APR_PROC_DETACH_DAEMONIZE);
1971
if (rv != APR_SUCCESS) {
1972
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
1973
"apr_proc_detach failed");
1974
return HTTP_INTERNAL_SERVER_ERROR;
1977
parent_pid = ap_my_pid = getpid();
1980
unixd_pre_config(ptemp);
1981
ap_listen_pre_config();
1982
ap_daemons_to_start = DEFAULT_START_DAEMON;
1983
min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
1984
max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
1985
ap_daemons_limit = server_limit;
1986
ap_threads_per_child = DEFAULT_THREADS_PER_CHILD;
1987
ap_pid_fname = DEFAULT_PIDLOG;
1988
ap_lock_fname = DEFAULT_LOCKFILE;
1989
ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
1990
ap_extended_status = 0;
1991
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
1992
ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
1995
apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
2000
static void worker_hooks(apr_pool_t *p)
2002
/* The worker open_logs phase must run before the core's, or stderr
2003
* will be redirected to a file, and the messages won't print to the
2006
static const char *const aszSucc[] = {"core.c", NULL};
2009
ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
2010
/* we need to set the MPM state before other pre-config hooks use MPM query
2011
* to retrieve it, so register as REALLY_FIRST
2013
ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
2016
static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
2019
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2024
ap_daemons_to_start = atoi(arg);
2028
static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
2031
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2036
min_spare_threads = atoi(arg);
2037
if (min_spare_threads <= 0) {
2038
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2039
"WARNING: detected MinSpareThreads set to non-positive.");
2040
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2041
"Resetting to 1 to avoid almost certain Apache failure.");
2042
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2043
"Please read the documentation.");
2044
min_spare_threads = 1;
2050
static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
2053
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2058
max_spare_threads = atoi(arg);
2062
static const char *set_max_clients (cmd_parms *cmd, void *dummy,
2066
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2071
/* It is ok to use ap_threads_per_child here because we are
2072
* sure that it gets set before MaxClients in the pre_config stage. */
2073
max_clients = atoi(arg);
2074
if (max_clients < ap_threads_per_child) {
2075
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2076
"WARNING: MaxClients (%d) must be at least as large",
2078
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2079
" as ThreadsPerChild (%d). Automatically",
2080
ap_threads_per_child);
2081
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2082
" increasing MaxClients to %d.",
2083
ap_threads_per_child);
2084
max_clients = ap_threads_per_child;
2086
ap_daemons_limit = max_clients / ap_threads_per_child;
2087
if ((max_clients > 0) && (max_clients % ap_threads_per_child)) {
2088
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2089
"WARNING: MaxClients (%d) is not an integer multiple",
2091
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2092
" of ThreadsPerChild (%d), lowering MaxClients to %d",
2093
ap_threads_per_child,
2094
ap_daemons_limit * ap_threads_per_child);
2095
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2096
" for a maximum of %d child processes,",
2098
max_clients = ap_daemons_limit * ap_threads_per_child;
2100
if (ap_daemons_limit > server_limit) {
2101
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2102
"WARNING: MaxClients of %d would require %d servers,",
2103
max_clients, ap_daemons_limit);
2104
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2105
" and would exceed the ServerLimit value of %d.",
2107
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2108
" Automatically lowering MaxClients to %d. To increase,",
2109
server_limit * ap_threads_per_child);
2110
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2111
" please see the ServerLimit directive.");
2112
ap_daemons_limit = server_limit;
2114
else if (ap_daemons_limit < 1) {
2115
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2116
"WARNING: Require MaxClients > 0, setting to 1");
2117
ap_daemons_limit = 1;
2122
static const char *set_threads_per_child (cmd_parms *cmd, void *dummy,
2125
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2130
ap_threads_per_child = atoi(arg);
2131
if (ap_threads_per_child > thread_limit) {
2132
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2133
"WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
2134
"value of %d", ap_threads_per_child,
2136
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2137
"threads, lowering ThreadsPerChild to %d. To increase, please"
2138
" see the", thread_limit);
2139
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2140
" ThreadLimit directive.");
2141
ap_threads_per_child = thread_limit;
2143
else if (ap_threads_per_child < 1) {
2144
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2145
"WARNING: Require ThreadsPerChild > 0, setting to 1");
2146
ap_threads_per_child = 1;
2151
static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
2153
int tmp_server_limit;
2155
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2160
tmp_server_limit = atoi(arg);
2161
/* you cannot change ServerLimit across a restart; ignore
2164
if (first_server_limit &&
2165
tmp_server_limit != server_limit) {
2166
/* how do we log a message? the error log is a bit bucket at this
2167
* point; we'll just have to set a flag so that ap_mpm_run()
2168
* logs a warning later
2170
changed_limit_at_restart = 1;
2173
server_limit = tmp_server_limit;
2175
if (server_limit > MAX_SERVER_LIMIT) {
2176
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2177
"WARNING: ServerLimit of %d exceeds compile time limit "
2178
"of %d servers,", server_limit, MAX_SERVER_LIMIT);
2179
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2180
" lowering ServerLimit to %d.", MAX_SERVER_LIMIT);
2181
server_limit = MAX_SERVER_LIMIT;
2183
else if (server_limit < 1) {
2184
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2185
"WARNING: Require ServerLimit > 0, setting to 1");
2191
static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg)
2193
int tmp_thread_limit;
2195
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2200
tmp_thread_limit = atoi(arg);
2201
/* you cannot change ThreadLimit across a restart; ignore
2204
if (first_thread_limit &&
2205
tmp_thread_limit != thread_limit) {
2206
/* how do we log a message? the error log is a bit bucket at this
2207
* point; we'll just have to set a flag so that ap_mpm_run()
2208
* logs a warning later
2210
changed_limit_at_restart = 1;
2213
thread_limit = tmp_thread_limit;
2215
if (thread_limit > MAX_THREAD_LIMIT) {
2216
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2217
"WARNING: ThreadLimit of %d exceeds compile time limit "
2218
"of %d servers,", thread_limit, MAX_THREAD_LIMIT);
2219
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2220
" lowering ThreadLimit to %d.", MAX_THREAD_LIMIT);
2221
thread_limit = MAX_THREAD_LIMIT;
2223
else if (thread_limit < 1) {
2224
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2225
"WARNING: Require ThreadLimit > 0, setting to 1");
2231
static const command_rec worker_cmds[] = {
2232
UNIX_DAEMON_COMMANDS,
2234
AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
2235
"Number of child processes launched at server startup"),
2236
AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
2237
"Minimum number of idle threads, to handle request spikes"),
2238
AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
2239
"Maximum number of idle threads"),
2240
AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
2241
"Maximum number of threads alive at the same time"),
2242
AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
2243
"Number of threads each child creates"),
2244
AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
2245
"Maximum number of child processes for this run of Apache"),
2246
AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
2247
"Maximum number of worker threads per child process for this run of Apache - Upper limit for ThreadsPerChild"),
2248
AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
2252
module AP_MODULE_DECLARE_DATA mpm_worker_module = {
2254
ap_mpm_rewrite_args, /* hook to run before apache parses args */
2255
NULL, /* create per-directory config structure */
2256
NULL, /* merge per-directory config structures */
2257
NULL, /* create per-server config structure */
2258
NULL, /* merge per-server config structures */
2259
worker_cmds, /* command apr_table_t */
2260
worker_hooks /* register_hooks */