Apache HTTPD
worker.c
Go to the documentation of this file.
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
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.
22 */
23
24#include "apr.h"
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"
32#include "apr_poll.h"
33
34#include <stdlib.h>
35
36#define APR_WANT_STRFUNC
37#include "apr_want.h"
38
39#if APR_HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#if APR_HAVE_SYS_SOCKET_H
43#include <sys/socket.h>
44#endif
45#if APR_HAVE_SYS_WAIT_H
46#include <sys/wait.h>
47#endif
48#ifdef HAVE_SYS_PROCESSOR_H
49#include <sys/processor.h> /* for bindprocessor() */
50#endif
51
52#if !APR_HAS_THREADS
53#error The Worker MPM requires APR threads, but they are unavailable.
54#endif
55
56#include "ap_config.h"
57#include "httpd.h"
58#include "http_main.h"
59#include "http_log.h"
60#include "http_config.h" /* for read_config */
61#include "http_core.h" /* for get_remote_host */
62#include "http_connection.h"
63#include "ap_mpm.h"
64#include "mpm_common.h"
65#include "ap_listen.h"
66#include "scoreboard.h"
67#include "mpm_fdqueue.h"
68#include "mpm_default.h"
69#include "util_mutex.h"
70#include "unixd.h"
71
72#include <signal.h>
73#include <limits.h> /* for INT_MAX */
74
75/* Limit on the total --- clients will be locked out if more servers than
76 * this are needed. It is intended solely to keep the server from crashing
77 * when things get out of hand.
78 *
79 * We keep a hard maximum number of servers, for two reasons --- first off,
80 * in case something goes seriously wrong, we want to stop the fork bomb
81 * short of actually crashing the machine we're running on by filling some
82 * kernel table. Secondly, it keeps the size of the scoreboard file small
83 * enough that we can read the whole thing without worrying too much about
84 * the overhead.
85 */
86#ifndef DEFAULT_SERVER_LIMIT
87#define DEFAULT_SERVER_LIMIT 16
88#endif
89
90/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
91 * some sort of compile-time limit to help catch typos.
92 */
93#ifndef MAX_SERVER_LIMIT
94#define MAX_SERVER_LIMIT 20000
95#endif
96
97/* Limit on the threads per process. Clients will be locked out if more than
98 * this * server_limit are needed.
99 *
100 * We keep this for one reason it keeps the size of the scoreboard file small
101 * enough that we can read the whole thing without worrying too much about
102 * the overhead.
103 */
104#ifndef DEFAULT_THREAD_LIMIT
105#define DEFAULT_THREAD_LIMIT 64
106#endif
107
108/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
109 * some sort of compile-time limit to help catch typos.
110 */
111#ifndef MAX_THREAD_LIMIT
112#define MAX_THREAD_LIMIT 20000
113#endif
114
115/*
116 * Actual definitions of config globals
117 */
118
119static int threads_per_child = 0; /* Worker threads per child */
120static int ap_daemons_to_start = 0;
121static int min_spare_threads = 0;
122static int max_spare_threads = 0;
123static int ap_daemons_limit = 0;
124static int max_workers = 0;
125static int server_limit = 0;
126static int thread_limit = 0;
127static int had_healthy_child = 0;
128static volatile int dying = 0;
129static int workers_may_exit = 0;
131static int listener_may_exit = 0;
132static int listener_is_wakeable = 0; /* Pollset supports APR_POLLSET_WAKEABLE */
134static int num_listensocks = 0;
135static int resource_shortage = 0;
139
140
141/* data retained by worker across load/unload of the module
142 * allocated on first call to pre-config hook; located on
143 * subsequent calls to pre-config hook
144 */
145typedef struct worker_retained_data {
147
153 /*
154 * The max child slot ever assigned, preserved across restarts. Necessary
155 * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts.
156 * We use this value to optimize routines that have to scan the entire
157 * scoreboard.
158 */
160 /*
161 * idle_spawn_rate is the number of children that will be spawned on the
162 * next maintenance cycle if there aren't enough idle servers. It is
163 * maintained per listeners bucket, doubled up to MAX_SPAWN_RATE, and
164 * reset only when a cycle goes by without the need to spawn.
165 */
167#ifndef MAX_SPAWN_RATE
168#define MAX_SPAWN_RATE (32)
169#endif
173
179static worker_child_bucket *all_buckets, /* All listeners buckets */
180 *my_bucket; /* Current child bucket */
181
182#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
183
184/* The structure used to pass unique initialization info to each thread */
185typedef struct {
186 int pid;
187 int tid;
188 int sd;
189} proc_info;
190
191/* Structure used to pass information to the thread responsible for
192 * creating the rest of the threads.
193 */
194typedef struct {
195 apr_thread_t **threads;
196 apr_thread_t *listener;
197 int child_num_arg;
198 apr_threadattr_t *threadattr;
200
201#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
202
203/* The worker MPM respects a couple of runtime flags that can aid
204 * in debugging. Setting the -DNO_DETACH flag will prevent the root process
205 * from detaching from its controlling terminal. Additionally, setting
206 * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
207 * child_main loop running in the process which originally started up.
208 * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
209 * early in standalone_main; just continue through. This is the server
210 * trying to kill off any child processes which it might have lying
211 * around --- Apache doesn't keep track of their pids, it just sends
212 * SIGHUP to the process group, ignoring it in the root process.
213 * Continue through and you'll be fine.).
214 */
215
216static int one_process = 0;
217
218#ifdef DEBUG_SIGSTOP
220#endif
221
222static apr_pool_t *pconf; /* Pool for config stuff */
223static apr_pool_t *pchild; /* Pool for httpd child stuff */
224static apr_pool_t *pruntime; /* Pool for MPM threads stuff */
225
226static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
227 thread. Use this instead */
230
231#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
232#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)
233#else
234#define SAFE_ACCEPT(stmt) (stmt)
235#endif
236
237/* The LISTENER_SIGNAL signal will be sent from the main thread to the
238 * listener thread to wake it up for graceful termination (what a child
239 * process from an old generation does when the admin does "apachectl
240 * graceful"). This signal will be blocked in all threads of a child
241 * process except for the listener thread.
242 */
243#define LISTENER_SIGNAL SIGHUP
244
245/* The WORKER_SIGNAL signal will be sent from the main thread to the
246 * worker threads during an ungraceful restart or shutdown.
247 * This ensures that on systems (i.e., Linux) where closing the worker
248 * socket doesn't awake the worker thread when it is polling on the socket
249 * (especially in apr_wait_for_io_or_timeout() when handling
250 * Keep-Alive connections), close_worker_sockets() and join_workers()
251 * still function in timely manner and allow ungraceful shutdowns to
252 * proceed to completion. Otherwise join_workers() doesn't return
253 * before the main process decides the child process is non-responsive
254 * and sends a SIGKILL.
255 */
256#define WORKER_SIGNAL AP_SIG_GRACEFUL
257
258/* An array of socket descriptors in use by each thread used to
259 * perform a non-graceful (forced) shutdown of the server. */
261
262static void close_worker_sockets(void)
263{
264 int i;
265 for (i = 0; i < threads_per_child; i++) {
266 if (worker_sockets[i]) {
269 }
270 }
271}
272
273static void wakeup_listener(void)
274{
276
277 /* Unblock the listener if it's poll()ing */
280 }
281
282 /* unblock the listener if it's waiting for a worker */
284
285 if (!listener_os_thread) {
286 /* XXX there is an obscure path that this doesn't handle perfectly:
287 * right after listener thread is created but before
288 * listener_os_thread is set, the first worker thread hits an
289 * error and starts graceful termination
290 */
291 return;
292 }
293 /*
294 * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
295 * platforms and wake up the listener thread since it is the only thread
296 * with SIGHUP unblocked, but that doesn't work on Linux
297 */
298#ifdef HAVE_PTHREAD_KILL
300#else
302#endif
303}
304
305#define ST_INIT 0
306#define ST_GRACEFUL 1
307#define ST_UNGRACEFUL 2
308
310
311static void signal_threads(int mode)
312{
313 if (terminate_mode == mode) {
314 return;
315 }
317 retained->mpm->mpm_state = AP_MPMQ_STOPPING;
318
319 /* in case we weren't called from the listener thread, wake up the
320 * listener thread
321 */
323
324 /* for ungraceful termination, let the workers exit now;
325 * for graceful termination, the listener thread will notify the
326 * workers to exit once it has stopped accepting new connections
327 */
328 if (mode == ST_UNGRACEFUL) {
331 close_worker_sockets(); /* forcefully kill all current connections */
332 }
333
335}
336
337static int worker_query(int query_code, int *result, apr_status_t *rv)
338{
339 *rv = APR_SUCCESS;
340 switch (query_code) {
343 break;
346 break;
349 break;
352 break;
355 break;
358 break;
360 *result = 0;
361 break;
364 break;
366 *result = 0;
367 break;
370 break;
373 break;
376 break;
378 *result = retained->mpm->mpm_state;
379 break;
381 *result = retained->mpm->my_generation;
382 break;
383 default:
384 *rv = APR_ENOTIMPL;
385 break;
386 }
387 return OK;
388}
389
391{
392 if (childnum != -1) { /* child had a scoreboard slot? */
398 }
399 else {
401 }
402}
403
411
413{
415 "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
416 "%" APR_PID_T_FMT "%s",
417 newpid,
420 " (quiescing)" : "");
425 /* Don't forget about this exiting child process, or we
426 * won't be able to kill it if it doesn't exit by the
427 * time the server is shut down.
428 */
431}
432
433static const char *worker_get_name(void)
434{
435 return "worker";
436}
437
438/* a clean exit from a child with proper cleanup */
439static void clean_child_exit(int code) __attribute__ ((noreturn));
440static void clean_child_exit(int code)
441{
442 retained->mpm->mpm_state = AP_MPMQ_STOPPING;
443 if (terminate_mode == ST_INIT) {
445 }
446
447 if (pchild) {
449 }
450
451 if (one_process) {
452 worker_note_child_killed(/* slot */ 0, 0, 0);
453 }
454
455 exit(code);
456}
457
458static void just_die(int sig)
459{
461}
462
463/*****************************************************************
464 * Connection structures and accounting...
465 */
466
467static int child_fatal;
468
469/*****************************************************************
470 * Here follows a long bunch of generic server bookkeeping stuff...
471 */
472
473/*****************************************************************
474 * Child process main loop.
475 */
476
495
496/* requests_this_child has gone to zero or below. See if the admin coded
497 "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way
498 simplifies the hot path in worker_thread */
499static void check_infinite_requests(void)
500{
503 }
504 else {
505 requests_this_child = INT_MAX; /* keep going */
506 }
507}
508
509static void unblock_signal(int sig)
510{
512
515#if defined(SIGPROCMASK_SETS_THREAD_MASK)
517#else
519#endif
520}
521
522static void dummy_signal_handler(int sig)
523{
524 /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
525 * then we don't need this goofy function.
526 */
527}
528
529static void accept_mutex_error(const char *func, apr_status_t rv, int process_slot)
530{
531 int level = APLOG_EMERG;
532
535 level = APLOG_DEBUG; /* common to get these at restart time */
536 }
537 else if (requests_this_child == INT_MAX
541 "apr_proc_mutex_%s failed "
542 "before this child process served any requests.",
543 func);
545 }
547 "apr_proc_mutex_%s failed. Attempting to "
548 "shutdown process gracefully.", func);
550}
551
553{
554 proc_info * ti = dummy;
555 int process_slot = ti->pid;
556 void *csd = NULL;
557 apr_pool_t *ptrans = NULL; /* Pool for per-transaction stuff */
558 apr_status_t rv;
560 int have_idle_worker = 0;
561 int last_poll_idx = 0;
562
563 free(ti);
564
565 /* Unblock the signal used to wake this thread up, and set a handler for
566 * it.
567 */
570
571 /* TODO: Switch to a system where threads reuse the results from earlier
572 poll calls - manoj */
573 while (1) {
574 /* TODO: requests_this_child should be synchronized - aaron */
575 if (requests_this_child <= 0) {
577 }
578 if (listener_may_exit) break;
579
580 if (!have_idle_worker) {
582 if (APR_STATUS_IS_EOF(rv)) {
583 break; /* we've been signaled to die now */
584 }
585 else if (rv != APR_SUCCESS) {
587 "apr_queue_info_wait failed. Attempting to "
588 " shutdown process gracefully.");
590 break;
591 }
593 }
594
595 /* We've already decremented the idle worker count inside
596 * ap_queue_info_wait_for_idler. */
597
599 != APR_SUCCESS) {
600
601 if (!listener_may_exit) {
602 accept_mutex_error("lock", rv, process_slot);
603 }
604 break; /* skip the lock release */
605 }
606
607 if (!my_bucket->listeners->next) {
608 /* Only one listener, so skip the poll */
610 }
611 else {
612 while (!listener_may_exit) {
614 const apr_pollfd_t *pdesc;
615
617 if (rv != APR_SUCCESS) {
618 if (APR_STATUS_IS_EINTR(rv)) {
619 continue;
620 }
621
622 /* apr_pollset_poll() will only return errors in catastrophic
623 * circumstances. Let's try exiting gracefully, for now. */
625 "apr_pollset_poll: (listen)");
627 }
628
629 if (listener_may_exit) break;
630
631 /* We can always use pdesc[0], but sockets at position N
632 * could end up completely starved of attention in a very
633 * busy server. Therefore, we round-robin across the
634 * returned set of descriptors. While it is possible that
635 * the returned set of descriptors might flip around and
636 * continue to starve some sockets, we happen to know the
637 * internal pollset implementation retains ordering
638 * stability of the sockets. Thus, the round-robin should
639 * ensure that a socket will eventually be serviced.
640 */
641 if (last_poll_idx >= numdesc)
642 last_poll_idx = 0;
643
644 /* Grab a listener record from the client_data of the poll
645 * descriptor, and advance our saved index to round-robin
646 * the next fetch.
647 *
648 * ### hmm... this descriptor might have POLLERR rather
649 * ### than POLLIN
650 */
651 lr = pdesc[last_poll_idx++].client_data;
652 break;
653
654 } /* while */
655
656 } /* if/else */
657
658 if (!listener_may_exit) {
659 /* the following pops a recycled ptrans pool off a stack */
661 if (ptrans == NULL) {
662 /* we can't use a recycled transaction pool this time.
663 * create a new transaction pool */
665
670 apr_pool_tag(ptrans, "transaction");
671 }
672 rv = lr->accept_func(&csd, lr, ptrans);
673 /* later we trash rv and rely on csd to indicate success/failure */
675
676 if (rv == APR_EGENERAL) {
677 /* E[NM]FILE, ENOMEM, etc */
680 }
682 != APR_SUCCESS) {
683
684 if (listener_may_exit) {
685 break;
686 }
687 accept_mutex_error("unlock", rv, process_slot);
688 }
689 if (csd != NULL) {
691 if (rv) {
692 /* trash the connection; we couldn't queue the connected
693 * socket to a worker
694 */
697 "ap_queue_push_socket failed");
698 }
699 else {
701 }
702 }
703 }
704 else {
706 != APR_SUCCESS) {
707 int level = APLOG_EMERG;
708
711 level = APLOG_DEBUG; /* common to get these at restart time */
712 }
714 "apr_proc_mutex_unlock failed. Attempting to "
715 "shutdown process gracefully.");
717 }
718 break;
719 }
720 }
721
725 dying = 1;
727
728 /* wake up the main thread */
730
732 return NULL;
733}
734
735/* XXX For ungraceful termination/restart, we definitely don't want to
736 * wait for active connections to finish but we may want to wait
737 * for idle workers to get out of the queue code and release mutexes,
738 * since those mutexes are cleaned up pretty soon and some systems
739 * may not react favorably (i.e., segfault) if operations are attempted
740 * on cleaned-up mutexes.
741 */
743{
744 proc_info * ti = dummy;
745 int process_slot = ti->pid;
746 int thread_slot = ti->tid;
748 apr_bucket_alloc_t *bucket_alloc;
750 apr_pool_t *ptrans; /* Pool for per-transaction stuff */
751 apr_status_t rv;
752 int is_idle = 0;
753
754 free(ti);
755
761
762#ifdef HAVE_PTHREAD_KILL
765#endif
766
767 while (!workers_may_exit) {
768 if (!is_idle) {
771 if (rv != APR_SUCCESS) {
773 "ap_queue_info_set_idle failed. Attempting to "
774 "shutdown process gracefully.");
776 break;
777 }
778 is_idle = 1;
779 }
780
784 if (workers_may_exit) {
785 break;
786 }
788
789 if (rv != APR_SUCCESS) {
790 /* We get APR_EOF during a graceful shutdown once all the connections
791 * accepted by this server process have been handled.
792 */
793 if (APR_STATUS_IS_EOF(rv)) {
794 break;
795 }
796 /* We get APR_EINTR whenever ap_queue_pop_*() has been interrupted
797 * from an explicit call to ap_queue_interrupt_all(). This allows
798 * us to unblock threads stuck in ap_queue_pop_*() when a shutdown
799 * is pending.
800 *
801 * If workers_may_exit is set and this is ungraceful termination/
802 * restart, we are bound to get an error on some systems (e.g.,
803 * AIX, which sanity-checks mutex operations) since the queue
804 * may have already been cleaned up. Don't log the "error" if
805 * workers_may_exit is set.
806 */
807 else if (APR_STATUS_IS_EINTR(rv)) {
808 goto worker_pop;
809 }
810 /* We got some other error. */
811 else if (!workers_may_exit) {
813 "ap_queue_pop_socket failed");
814 }
815 continue;
816 }
817 is_idle = 0;
819 bucket_alloc = apr_bucket_alloc_create(ptrans);
825 }
826
830
832 return NULL;
833}
834
835static int check_signal(int signum)
836{
837 switch (signum) {
838 case SIGTERM:
839 case SIGINT:
840 return 1;
841 }
842 return 0;
843}
844
846{
847 int my_child_num = ts->child_num_arg;
848 apr_threadattr_t *thread_attr = ts->threadattr;
850 apr_status_t rv;
851
852 my_info = (proc_info *)ap_malloc(sizeof(proc_info));
854 my_info->tid = -1; /* listener thread doesn't have a thread slot */
855 my_info->sd = 0;
856 rv = ap_thread_create(&ts->listener, thread_attr, listener_thread,
858 if (rv != APR_SUCCESS) {
860 "ap_thread_create: unable to create listener thread");
861 /* let the parent decide how bad this really is */
863 }
865}
866
867static void setup_threads_runtime(void)
868{
870 int pollset_flags;
871 apr_status_t rv;
872
873 /* All threads (listener, workers) and synchronization objects (queues,
874 * pollset, mutexes...) created here should have at least the lifetime of
875 * the connections they handle (i.e. ptrans). We can't use this thread's
876 * self pool because all these objects survive it, nor use pchild or pconf
877 * directly because this starter thread races with other modules' runtime,
878 * nor finally pchild (or subpool thereof) because it is killed explicitly
879 * before pconf (thus connections/ptrans can live longer, which matters in
880 * ONE_PROCESS mode). So this leaves us with a subpool of pconf, created
881 * before any ptrans hence destroyed after.
882 */
884 apr_pool_tag(pruntime, "mpm_runtime");
885
886 /* We must create the fd queues before we start up the listener
887 * and worker threads. */
889 if (rv != APR_SUCCESS) {
891 "ap_queue_create() failed");
893 }
894
897 if (rv != APR_SUCCESS) {
899 "ap_queue_info_create() failed");
901 }
902
903 /* Create the main pollset. When APR_POLLSET_WAKEABLE is asked we account
904 * for the wakeup pipe explicitely with num_listensocks+1 because some
905 * pollset implementations don't do it implicitely in APR.
906 */
910 if (rv == APR_SUCCESS) {
912 }
913 else {
917 }
918 if (rv != APR_SUCCESS) {
920 "Couldn't create pollset in thread;"
921 " check system or user limits");
922 /* let the parent decide how bad this really is */
924 }
925
926 for (lr = my_bucket->listeners; lr != NULL; lr = lr->next) {
927 apr_pollfd_t *pfd = apr_pcalloc(pruntime, sizeof *pfd);
928
930 pfd->desc.s = lr->sd;
931 pfd->reqevents = APR_POLLIN;
932 pfd->client_data = lr;
933
935 if (rv != APR_SUCCESS) {
937 "Couldn't create add listener to pollset;"
938 " check system or user limits");
939 /* let the parent decide how bad this really is */
941 }
942
943 lr->accept_func = ap_unixd_accept;
944 }
945
947 sizeof(apr_socket_t *));
948}
949
950/* XXX under some circumstances not understood, children can get stuck
951 * in start_threads forever trying to take over slots which will
952 * never be cleaned up; for now there is an APLOG_DEBUG message issued
953 * every so often when this condition occurs
954 */
956{
957 thread_starter *ts = dummy;
958 apr_thread_t **threads = ts->threads;
959 apr_threadattr_t *thread_attr = ts->threadattr;
960 int my_child_num = ts->child_num_arg;
962 apr_status_t rv;
963 int threads_created = 0;
964 int listener_started = 0;
966 int loops, i;
967
969 while (1) {
970 /* threads_per_child does not include the listener thread */
971 for (i = 0; i < threads_per_child; i++) {
973
975 continue;
976 }
977
978 my_info = (proc_info *)ap_malloc(sizeof(proc_info));
979 my_info->pid = my_child_num;
980 my_info->tid = i;
981 my_info->sd = 0;
982
983 /* We are creating threads right now */
986 /* We let each thread update its own scoreboard entry. This is
987 * done because it lets us deal with tid better.
988 */
989 rv = ap_thread_create(&threads[i], thread_attr,
991 if (rv != APR_SUCCESS) {
993 "ap_thread_create: unable to create worker thread");
994 /* let the parent decide how bad this really is */
996 }
998 }
999 /* Start the listener only when there are workers available */
1002 listener_started = 1;
1003 }
1005 break;
1006 }
1007 /* wait for previous generation to clean up an entry */
1009 ++loops;
1010 if (loops % 120 == 0) { /* every couple of minutes */
1013 "child %" APR_PID_T_FMT " isn't taking over "
1014 "slots very quickly (%d of %d)",
1016 }
1018 }
1019 }
1020
1021 /* What state should this child_main process be listed as in the
1022 * scoreboard...?
1023 * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
1024 * (request_rec *) NULL);
1025 *
1026 * This state should be listed separately in the scoreboard, in some kind
1027 * of process_status, not mixed in with the worker threads' status.
1028 * "life_status" is almost right, but it's in the worker's structure, and
1029 * the name could be clearer. gla
1030 */
1032 return NULL;
1033}
1034
1035static void join_workers(apr_thread_t *listener, apr_thread_t **threads,
1036 int mode)
1037{
1038 int i;
1040
1041 if (listener) {
1042 int iter;
1043
1044 /* deal with a rare timing window which affects waking up the
1045 * listener thread... if the signal sent to the listener thread
1046 * is delivered between the time it verifies that the
1047 * listener_may_exit flag is clear and the time it enters a
1048 * blocking syscall, the signal didn't do any good... work around
1049 * that by sleeping briefly and sending it again
1050 */
1051
1052 iter = 0;
1053 while (!dying) {
1055 if (dying || ++iter > 10) {
1056 break;
1057 }
1058 /* listener has not stopped accepting yet */
1060 "listener has not stopped accepting yet (%d iter)", iter);
1062 }
1063 if (iter > 10) {
1065 "the listener thread didn't exit");
1066 }
1067 else {
1068 rv = apr_thread_join(&thread_rv, listener);
1069 if (rv != APR_SUCCESS) {
1071 "apr_thread_join: unable to join listener thread");
1072 }
1073 }
1074 }
1075
1076 for (i = 0; i < threads_per_child; i++) {
1077 if (threads[i]) { /* if we ever created this thread */
1078 if (mode != ST_GRACEFUL) {
1079#ifdef HAVE_PTHREAD_KILL
1081
1084#endif
1085 }
1086
1087 rv = apr_thread_join(&thread_rv, threads[i]);
1088 if (rv != APR_SUCCESS) {
1090 "apr_thread_join: unable to join worker "
1091 "thread %d",
1092 i);
1093 }
1094 }
1095 }
1096}
1097
1099{
1101
1102 start_thread_may_exit = 1; /* tell it to give up in case it is still
1103 * trying to take over slots from a
1104 * previous generation
1105 */
1107 if (rv != APR_SUCCESS) {
1109 "apr_thread_join: unable to join the start "
1110 "thread");
1111 }
1112}
1113
1114static void child_main(int child_num_arg, int child_bucket)
1115{
1116 apr_thread_t **threads;
1117 apr_status_t rv;
1118 thread_starter *ts;
1119 apr_threadattr_t *thread_attr;
1121 int i;
1122
1123 /* for benefit of any hooks that run as this child initializes */
1124 retained->mpm->mpm_state = AP_MPMQ_STARTING;
1125
1126 ap_my_pid = getpid();
1128
1129 /* Get a sub context for global allocations in this child, so that
1130 * we can have cleanups occur when the child exits.
1131 */
1133 apr_pool_tag(pchild, "pchild");
1134
1135#if AP_HAS_THREAD_LOCAL
1136 if (!one_process) {
1138 if ((rv = ap_thread_main_create(&thd, pchild))) {
1140 "Couldn't initialize child main thread");
1142 }
1143 }
1144#endif
1145
1146 /* close unused listeners and pods */
1147 for (i = 0; i < retained->mpm->num_buckets; i++) {
1148 if (i != child_bucket) {
1151 }
1152 }
1153
1154 /*stuff to do before we switch id's, so we have permissions.*/
1156
1159 pchild));
1160 if (rv != APR_SUCCESS) {
1162 "Couldn't initialize cross-process lock in child");
1164 }
1165
1166 /* done with init critical section */
1169 }
1170
1171 /* Just use the standard apr_setup_signal_thread to block all signals
1172 * from being received. The child processes no longer use signals for
1173 * any communication with the parent process. Let's also do this before
1174 * child_init() hooks are called and possibly create threads that
1175 * otherwise could "steal" (implicitly) MPM's signals.
1176 */
1178 if (rv != APR_SUCCESS) {
1180 "Couldn't initialize signal thread");
1182 }
1183
1185
1188 }
1189 else {
1190 /* coding a value of zero means infinity */
1192 }
1193
1194 /* Setup threads */
1195
1196 /* Globals used by signal_threads() so to be initialized before */
1198
1199 /* clear the storage; we may not create all our threads immediately,
1200 * and we want a 0 entry to indicate a thread which was not created
1201 */
1202 threads = (apr_thread_t **)ap_calloc(1,
1203 sizeof(apr_thread_t *) * threads_per_child);
1204 ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts));
1205
1206 apr_threadattr_create(&thread_attr, pchild);
1207 /* 0 means PTHREAD_CREATE_JOINABLE */
1208 apr_threadattr_detach_set(thread_attr, 0);
1209
1210 if (ap_thread_stacksize != 0) {
1212 if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
1214 "WARNING: ThreadStackSize of %" APR_SIZE_T_FMT " is "
1215 "inappropriate, using default",
1217 }
1218 }
1219
1220 ts->threads = threads;
1221 ts->listener = NULL;
1222 ts->child_num_arg = child_num_arg;
1223 ts->threadattr = thread_attr;
1224
1226 ts, pchild);
1227 if (rv != APR_SUCCESS) {
1229 "ap_thread_create: unable to create worker thread");
1230 /* let the parent decide how bad this really is */
1232 }
1233
1234 retained->mpm->mpm_state = AP_MPMQ_RUNNING;
1235
1236 /* If we are only running in one_process mode, we will want to
1237 * still handle signals. */
1238 if (one_process) {
1239 /* Block until we get a terminating signal. */
1241 /* make sure the start thread has finished; signal_threads()
1242 * and join_workers() depend on that
1243 */
1244 /* XXX join_start_thread() won't be awakened if one of our
1245 * threads encounters a critical error and attempts to
1246 * shutdown this child
1247 */
1249 signal_threads(ST_UNGRACEFUL); /* helps us terminate a little more
1250 * quickly than the dispatch of the signal thread
1251 * beats the Pipe of Death and the browsers
1252 */
1253 /* A terminating signal was received. Now join each of the
1254 * workers to clean them up.
1255 * If the worker already exited, then the join frees
1256 * their resources and returns.
1257 * If the worker hasn't exited, then this blocks until
1258 * they have (then cleans up).
1259 */
1260 join_workers(ts->listener, threads, ST_UNGRACEFUL);
1261 }
1262 else { /* !one_process */
1263 /* remove SIGTERM from the set of blocked signals... if one of
1264 * the other threads in the process needs to take us down
1265 * (e.g., for MaxConnectionsPerChild) it will send us SIGTERM
1266 */
1269 /* Watch for any messages from the parent over the POD */
1270 while (1) {
1272 if (rv == AP_MPM_PODX_NORESTART) {
1273 /* see if termination was triggered while we slept */
1274 switch(terminate_mode) {
1275 case ST_GRACEFUL:
1277 break;
1278 case ST_UNGRACEFUL:
1280 break;
1281 }
1282 }
1283 if (rv == AP_MPM_PODX_GRACEFUL || rv == AP_MPM_PODX_RESTART) {
1284 /* make sure the start thread has finished;
1285 * signal_threads() and join_workers depend on that
1286 */
1289 break;
1290 }
1291 }
1292
1293 /* A terminating signal was received. Now join each of the
1294 * workers to clean them up.
1295 * If the worker already exited, then the join frees
1296 * their resources and returns.
1297 * If the worker hasn't exited, then this blocks until
1298 * they have (then cleans up).
1299 */
1300 join_workers(ts->listener, threads,
1302 }
1303
1304 free(threads);
1305
1307}
1308
1309static int make_child(server_rec *s, int slot, int bucket)
1310{
1311 int pid;
1312
1313 if (slot + 1 > retained->max_daemons_limit) {
1315 }
1316
1317 if (one_process) {
1318 my_bucket = &all_buckets[0];
1319
1321 child_main(slot, 0);
1322 /* NOTREACHED */
1323 ap_assert(0);
1324 return -1;
1325 }
1326
1327 if ((pid = fork()) == -1) {
1329 "fork: Unable to fork new process");
1330 /* fork didn't succeed. There's no need to touch the scoreboard;
1331 * if we were trying to replace a failed child process, then
1332 * server_main_loop() marked its workers SERVER_DEAD, and if
1333 * we were trying to replace a child process that exited normally,
1334 * its worker_thread()s left SERVER_DEAD or SERVER_GRACEFUL behind.
1335 */
1336
1337 /* In case system resources are maxxed out, we don't want
1338 Apache running away with the CPU trying to fork over and
1339 over and over again. */
1341
1342 return -1;
1343 }
1344
1345 if (!pid) {
1346#if AP_HAS_THREAD_LOCAL
1348#endif
1349
1350 my_bucket = &all_buckets[bucket];
1351
1352#ifdef HAVE_BINDPROCESSOR
1353 /* By default, AIX binds to a single processor. This bit unbinds
1354 * children which will then bind to another CPU.
1355 */
1356 int status = bindprocessor(BINDPROCESS, (int)getpid(),
1358 if (status != OK)
1360 ap_server_conf, APLOGNO(00284)
1361 "processor unbind failed");
1362#endif
1364
1366 child_main(slot, bucket);
1367 /* NOTREACHED */
1368 ap_assert(0);
1369 return -1;
1370 }
1371
1372 if (ap_scoreboard_image->parent[slot].pid != 0) {
1373 /* This new child process is squatting on the scoreboard
1374 * entry owned by an exiting child process, which cannot
1375 * exit until all active requests complete.
1376 */
1378 }
1381 return 0;
1382}
1383
1384/* start up a bunch of children */
1386{
1387 int i;
1388
1389 for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
1390 if (ap_scoreboard_image->parent[i].pid != 0) {
1391 continue;
1392 }
1393 if (make_child(ap_server_conf, i, i % retained->mpm->num_buckets) < 0) {
1394 break;
1395 }
1397 }
1398}
1399
1401{
1402 int num_buckets = retained->mpm->num_buckets;
1405 int free_length;
1406 int totally_free_length = 0;
1408 int last_non_dead;
1409 int total_non_dead;
1410 int active_thread_count = 0;
1411 int i, j;
1412
1413 /* initialize the free_list */
1414 free_length = 0;
1415
1417 last_non_dead = -1;
1418 total_non_dead = 0;
1419
1420 for (i = 0; i < ap_daemons_limit; ++i) {
1421 /* Initialization to satisfy the compiler. It doesn't know
1422 * that threads_per_child is always > 0 */
1423 int any_dying_threads = 0;
1424 int any_dead_threads = 0;
1425 int all_dead_threads = 1;
1426 int child_threads_active = 0;
1427
1428 if (num_buckets > 1 && (i % num_buckets) != child_bucket) {
1429 /* We only care about child_bucket in this call */
1430 continue;
1431 }
1432 if (i >= retained->max_daemons_limit &&
1434 /* short cut if all active processes have been examined and
1435 * enough empty scoreboard slots have been found
1436 */
1437 break;
1438 }
1440 for (j = 0; j < threads_per_child; j++) {
1442
1443 /* XXX any_dying_threads is probably no longer needed GLA */
1448 (status == SERVER_DEAD ||
1450
1451 /* We consider a starting server as idle because we started it
1452 * at least a cycle ago, and if it still hasn't finished starting
1453 * then we're just going to swamp things worse by forking more.
1454 * So we hopefully won't need to fork more if we count it.
1455 * This depends on the ordering of SERVER_READY and SERVER_STARTING.
1456 */
1457 if (ps->pid != 0) { /* XXX just set all_dead_threads in outer for
1458 loop if no pid? not much else matters */
1459 if (status <= SERVER_READY &&
1460 !ps->quiescing &&
1461 ps->generation == retained->mpm->my_generation) {
1463 }
1466 }
1467 }
1468 }
1473 && (!ps->pid /* no process in the slot */
1474 || ps->quiescing)) { /* or at least one is going away */
1475 if (all_dead_threads) {
1476 /* great! we prefer these, because the new process can
1477 * start more threads sooner. So prioritize this slot
1478 * by putting it ahead of any slots with active threads.
1479 *
1480 * first, make room by moving a slot that's potentially still
1481 * in use to the end of the array
1482 */
1485 }
1486 else {
1487 /* slot is still in use - back of the bus
1488 */
1490 }
1491 ++free_length;
1492 }
1495 }
1496 /* XXX if (!ps->quiescing) is probably more reliable GLA */
1497 if (!any_dying_threads) {
1499 }
1500 if (ps->pid != 0) {
1501 last_non_dead = i;
1502 }
1503 }
1504
1506
1508 if (had_healthy_child) {
1509 /* Assume this is a transient error, even though it may not be. Leave
1510 * the server up in case it is able to serve some requests or the
1511 * problem will be resolved.
1512 */
1514 }
1515 else if (child_bucket < num_buckets - 1) {
1516 /* check for had_healthy_child up to the last child bucket */
1517 return;
1518 }
1519 else {
1520 /* looks like a basket case, as no child ever fully initialized; give up.
1521 */
1522 retained->mpm->shutdown_pending = 1;
1523 child_fatal = 1;
1525 ap_server_conf, APLOGNO(02325)
1526 "A resource shortage or other unrecoverable failure "
1527 "was encountered before any child process initialized "
1528 "successfully... httpd is exiting!");
1529 /* the child already logged the failure details */
1530 return;
1531 }
1532 }
1533
1535 /* Kill off one child */
1539 }
1541 /* terminate the free list */
1542 if (free_length == 0) { /* scoreboard is full, can't fork */
1543
1545 /* no threads are "inactive" - starting, stopping, etc. */
1546 /* have we reached MaxRequestWorkers, or just getting close? */
1547 if (0 == idle_thread_count) {
1549 /* only report this condition once */
1551 "server reached MaxRequestWorkers "
1552 "setting, consider raising the "
1553 "MaxRequestWorkers setting");
1555 }
1556 } else {
1559 "server is within MinSpareThreads of "
1560 "MaxRequestWorkers, consider raising the "
1561 "MaxRequestWorkers setting");
1563 }
1564 }
1565 }
1566 else {
1568 ap_server_conf, APLOGNO(00288)
1569 "scoreboard is full, not at MaxRequestWorkers");
1570 }
1572 }
1573 else {
1576 }
1579 ap_server_conf, APLOGNO(00289)
1580 "server seems busy, (you may need "
1581 "to increase StartServers, ThreadsPerChild "
1582 "or Min/MaxSpareThreads), "
1583 "spawning %d children, there are around %d idle "
1584 "threads, and %d total children", free_length,
1586 }
1587 for (i = 0; i < free_length; ++i) {
1589 }
1590 /* the next time around we want to spawn twice as many if this
1591 * wasn't good enough, but not if we've just done a graceful
1592 */
1595 }
1599 }
1600 }
1601 }
1602 else {
1604 }
1605}
1606
1608{
1609 int num_buckets = retained->mpm->num_buckets;
1610 int successive_kills = 0;
1612 int child_slot;
1615 apr_proc_t pid;
1616 int i;
1617
1618 while (!retained->mpm->restart_pending && !retained->mpm->shutdown_pending) {
1620
1621 if (pid.pid != -1) {
1625 /* fix race condition found in PR 39311
1626 * A child created at the same time as a graceful happens
1627 * can find the lock missing and create a fatal error.
1628 * It is not fatal for the last generation to be in this state.
1629 */
1630 if (child_slot < 0
1632 == retained->mpm->my_generation) {
1633 retained->mpm->shutdown_pending = 1;
1634 child_fatal = 1;
1635 return;
1636 }
1637 else {
1639 "Ignoring fatal error in child of previous "
1640 "generation (pid %ld).",
1641 (long)pid.pid);
1643 }
1644 }
1645 else if (processed_status == APEXIT_CHILDSICK) {
1646 /* tell perform_idle_server_maintenance to check into this
1647 * on the next timer pop
1648 */
1650 }
1651 /* non-fatal death... note that it's gone in the scoreboard. */
1652 if (child_slot >= 0) {
1654
1655 for (i = 0; i < threads_per_child; i++)
1657 SERVER_DEAD, NULL);
1658
1661 ps->quiescing = 0;
1663 /* resource shortage, minimize the fork rate */
1665 }
1668 /* we're still doing a 1-for-1 replacement of dead
1669 * children with new children
1670 */
1674 }
1675 }
1676 else if (ap_unregister_extra_mpm_process(pid.pid, &old_gen) == 1) {
1677 worker_note_child_killed(-1, /* already out of the scoreboard */
1678 pid.pid, old_gen);
1680 && old_gen == retained->mpm->my_generation) {
1681 /* resource shortage, minimize the fork rate */
1682 for (i = 0; i < num_buckets; i++) {
1684 }
1685 }
1686#if APR_HAS_OTHER_CHILD
1687 }
1689 status) == 0) {
1690 /* handled */
1691#endif
1692 }
1693 else if (retained->mpm->was_graceful) {
1694 /* Great, we've probably just lost a slot in the
1695 * scoreboard. Somehow we don't know about this child.
1696 */
1698 ap_server_conf, APLOGNO(00291)
1699 "long lost child came home! (pid %ld)",
1700 (long)pid.pid);
1701 }
1702 /* Don't perform idle maintenance when a child dies,
1703 * only do it when there's a timeout. Remember only a
1704 * finite number of children can die, and it's pretty
1705 * pathological for a lot to die suddenly. If a child is
1706 * killed by a signal (faulting) we want to restart it ASAP
1707 * though, up to 3 successive faults or we stop this until
1708 * a timeout happens again (to avoid the flood of fork()ed
1709 * processes that keep being killed early).
1710 */
1712 continue;
1713 }
1714 if (++successive_kills >= 3) {
1715 if (successive_kills % 10 == 3) {
1717 ap_server_conf, APLOGNO(10393)
1718 "children are killed successively!");
1719 }
1720 continue;
1721 }
1723 }
1724 else {
1725 successive_kills = 0;
1726 }
1727
1729 /* we hit a 1 second timeout in which none of the previous
1730 * generation of children needed to be reaped... so assume
1731 * they're all done, and pick up the slack if any is left.
1732 */
1735 /* In any event we really shouldn't do the code below because
1736 * few of the servers we just started are in the IDLE state
1737 * yet, so we'd mistakenly create an extra server.
1738 */
1739 continue;
1740 }
1741
1742 for (i = 0; i < num_buckets; i++) {
1744 }
1745 }
1746}
1747
1749{
1750 int num_buckets = retained->mpm->num_buckets;
1752 int i;
1753
1755
1756 if (!retained->mpm->was_graceful) {
1757 if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
1758 retained->mpm->mpm_state = AP_MPMQ_STOPPING;
1759 return !OK;
1760 }
1761 /* fix the generation number in the global score; we just got a new,
1762 * cleared scoreboard
1763 */
1765 }
1766
1768
1769 /* Don't thrash since num_buckets depends on the
1770 * system and the number of online CPU cores...
1771 */
1776 /* We want to create as much children at a time as the number of buckets,
1777 * so to optimally accept connections (evenly distributed across buckets).
1778 * Thus min_spare_threads should at least maintain num_buckets children,
1779 * and max_spare_threads allow num_buckets more children w/o triggering
1780 * immediately (e.g. num_buckets idle threads margin, one per bucket).
1781 */
1786
1787 /* If we're doing a graceful_restart then we're going to see a lot
1788 * of children exiting immediately when we get into the main loop
1789 * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty
1790 * rapidly... and for each one that exits we may start a new one, until
1791 * there are at least min_spare_threads idle threads, counting across
1792 * all children. But we may be permitted to start more children than
1793 * that, so we'll just keep track of how many we're
1794 * supposed to start up without the 1 second penalty between each fork.
1795 */
1799 }
1800 if (!retained->mpm->was_graceful) {
1803 }
1804 else {
1805 /* give the system some time to recover before kicking into
1806 * exponential mode */
1808 }
1809
1811 "%s configured -- resuming normal operations",
1814 "Server built: %s", ap_get_server_built());
1818 "Accept mutex: %s (default: %s)",
1819 (all_buckets[0].mutex)
1821 : "none",
1823 retained->mpm->mpm_state = AP_MPMQ_RUNNING;
1824
1826 retained->mpm->mpm_state = AP_MPMQ_STOPPING;
1827
1828 if (retained->mpm->shutdown_pending && retained->mpm->is_ungraceful) {
1829 /* Time to shut down:
1830 * Kill child processes, tell them to call child_exit, etc...
1831 */
1832 for (i = 0; i < num_buckets; i++) {
1835 }
1836 ap_reclaim_child_processes(1, /* Start with SIGTERM */
1838
1839 if (!child_fatal) {
1840 /* cleanup pid file on normal shutdown */
1843 ap_server_conf, APLOGNO(00295) "caught SIGTERM, shutting down");
1844 }
1845 return DONE;
1846 }
1847
1848 if (retained->mpm->shutdown_pending) {
1849 /* Time to gracefully shut down:
1850 * Kill child processes, tell them to call child_exit, etc...
1851 */
1852 int active_children;
1853 int index;
1854 apr_time_t cutoff = 0;
1855
1856 /* Close our listeners, and then ask our children to do same */
1858
1859 for (i = 0; i < num_buckets; i++) {
1862 }
1864
1865 if (!child_fatal) {
1866 /* cleanup pid file on normal shutdown */
1870 ", shutting down gracefully");
1871 }
1872
1874 cutoff = apr_time_now() +
1876 }
1877
1878 /* Don't really exit until each child has finished */
1879 retained->mpm->shutdown_pending = 0;
1880 do {
1881 /* Pause for a second */
1883
1884 /* Relieve any children which have now exited */
1886
1887 active_children = 0;
1888 for (index = 0; index < ap_daemons_limit; ++index) {
1889 if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
1890 active_children = 1;
1891 /* Having just one child is enough to stay around */
1892 break;
1893 }
1894 }
1895 } while (!retained->mpm->shutdown_pending && active_children &&
1897
1898 /* We might be here because we received SIGTERM, either
1899 * way, try and make sure that all of our processes are
1900 * really dead.
1901 */
1902 for (i = 0; i < num_buckets; i++) {
1905 }
1907
1908 return DONE;
1909 }
1910
1911 /* we've been told to restart */
1912 if (one_process) {
1913 /* not worth thinking about */
1914 return DONE;
1915 }
1916
1917 /* advance to the next generation */
1918 /* XXX: we really need to make sure this new generation number isn't in
1919 * use by any of the children.
1920 */
1921 ++retained->mpm->my_generation;
1923
1924 if (!retained->mpm->is_ungraceful) {
1926 AP_SIG_GRACEFUL_STRING " received. Doing graceful restart");
1927 /* wake up the children...time to die. But we'll have more soon */
1928 for (i = 0; i < num_buckets; i++) {
1931 }
1932
1933 /* This is mostly for debugging... so that we know what is still
1934 * gracefully dealing with existing request.
1935 */
1936
1937 }
1938 else {
1939 /* Kill 'em all. Since the child acts the same on the parents SIGTERM
1940 * and a SIGHUP, we may as well use the same signal, because some user
1941 * pthreads are stealing signals from us left and right.
1942 */
1943 for (i = 0; i < num_buckets; i++) {
1946 }
1947
1948 ap_reclaim_child_processes(1, /* Start with SIGTERM */
1951 "SIGHUP received. Attempting to restart");
1952 }
1953
1954 return OK;
1955}
1956
1957/* This really should be a post_config hook, but the error log is already
1958 * redirected by that point, so we need to do this in the open_logs phase.
1959 */
1961{
1962 int startup = 0;
1963 int level_flags = 0;
1964 int num_buckets = 0;
1966 apr_status_t rv;
1967 char id[16];
1968 int i;
1969
1970 pconf = p;
1971
1972 /* the reverse of pre_config, we want this only the first time around */
1973 if (retained->mpm->module_loads == 1) {
1974 startup = 1;
1976 }
1977
1980 (startup ? NULL : s),
1981 "no listening sockets available, shutting down");
1982 return !OK;
1983 }
1984
1985 if (one_process) {
1986 num_buckets = 1;
1987 }
1988 else if (retained->mpm->was_graceful) {
1989 /* Preserve the number of buckets on graceful restarts. */
1990 num_buckets = retained->mpm->num_buckets;
1991 }
1995 (startup ? NULL : s),
1996 "could not duplicate listeners");
1997 return !OK;
1998 }
1999
2001 for (i = 0; i < num_buckets; i++) {
2002 if (!one_process && /* no POD in one_process mode */
2003 (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) {
2005 (startup ? NULL : s),
2006 "could not open pipe-of-death");
2007 return !OK;
2008 }
2009 /* Initialize cross-process accept lock (safe accept needed only) */
2010 if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i),
2013 id, s, pconf, 0))))) {
2015 (startup ? NULL : s),
2016 "could not create accept mutex");
2017 return !OK;
2018 }
2020 }
2021
2022 if (retained->mpm->max_buckets < num_buckets) {
2023 int new_max, *new_ptr;
2024 new_max = retained->mpm->max_buckets * 2;
2025 if (new_max < num_buckets) {
2027 }
2028 new_ptr = (int *)apr_palloc(ap_pglobal, new_max * sizeof(int));
2029 if (retained->idle_spawn_rate) /* NULL at startup */
2031 retained->mpm->num_buckets * sizeof(int));
2033 retained->mpm->max_buckets = new_max;
2034 }
2035 if (retained->mpm->num_buckets < num_buckets) {
2036 int rate_max = 1;
2037 /* If new buckets are added, set their idle spawn rate to
2038 * the highest so far, so that they get filled as quickly
2039 * as the existing ones.
2040 */
2041 for (i = 0; i < retained->mpm->num_buckets; i++) {
2044 }
2045 }
2046 for (/* up to date i */; i < num_buckets; i++) {
2048 }
2049 }
2050 retained->mpm->num_buckets = num_buckets;
2051
2052 return OK;
2053}
2054
2056 apr_pool_t *ptemp)
2057{
2059 apr_status_t rv;
2060 const char *userdata_key = "mpm_worker_module";
2061
2062 debug = ap_exists_config_define("DEBUG");
2063
2064 if (debug) {
2065 foreground = one_process = 1;
2066 no_detach = 0;
2067 }
2068 else {
2069 one_process = ap_exists_config_define("ONE_PROCESS");
2070 no_detach = ap_exists_config_define("NO_DETACH");
2071 foreground = ap_exists_config_define("FOREGROUND");
2072 }
2073
2075
2077 if (!retained) {
2080 }
2081 retained->mpm->mpm_state = AP_MPMQ_STARTING;
2082 if (retained->mpm->baton != retained) {
2083 retained->mpm->was_graceful = 0;
2084 retained->mpm->baton = retained;
2085 }
2086 ++retained->mpm->module_loads;
2087
2088 /* sigh, want this only the second time around */
2089 if (retained->mpm->module_loads == 2) {
2090 if (!one_process && !foreground) {
2091 /* before we detach, setup crash handlers to log to errorlog */
2095 if (rv != APR_SUCCESS) {
2097 "apr_proc_detach failed");
2099 }
2100 }
2101 }
2102
2104
2116
2117 return OK;
2118}
2119
2121 apr_pool_t *ptemp, server_rec *s)
2122{
2123 int startup = 0;
2124
2125 /* the reverse of pre_config, we want this only the first time around */
2126 if (retained->mpm->module_loads == 1) {
2127 startup = 1;
2128 }
2129
2131 if (startup) {
2133 "WARNING: ServerLimit of %d exceeds compile-time "
2134 "limit of %d servers, decreasing to %d.",
2136 } else {
2138 "ServerLimit of %d exceeds compile-time limit "
2139 "of %d, decreasing to match",
2141 }
2143 }
2144 else if (server_limit < 1) {
2145 if (startup) {
2147 "WARNING: ServerLimit of %d not allowed, "
2148 "increasing to 1.", server_limit);
2149 } else {
2151 "ServerLimit of %d not allowed, increasing to 1",
2152 server_limit);
2153 }
2154 server_limit = 1;
2155 }
2156
2157 /* you cannot change ServerLimit across a restart; ignore
2158 * any such attempts
2159 */
2162 }
2164 /* don't need a startup console version here */
2166 "changing ServerLimit to %d from original value of %d "
2167 "not allowed during restart",
2170 }
2171
2173 if (startup) {
2175 "WARNING: ThreadLimit of %d exceeds compile-time "
2176 "limit of %d threads, decreasing to %d.",
2178 } else {
2180 "ThreadLimit of %d exceeds compile-time limit "
2181 "of %d, decreasing to match",
2183 }
2185 }
2186 else if (thread_limit < 1) {
2187 if (startup) {
2189 "WARNING: ThreadLimit of %d not allowed, "
2190 "increasing to 1.", thread_limit);
2191 } else {
2193 "ThreadLimit of %d not allowed, increasing to 1",
2194 thread_limit);
2195 }
2196 thread_limit = 1;
2197 }
2198
2199 /* you cannot change ThreadLimit across a restart; ignore
2200 * any such attempts
2201 */
2204 }
2206 /* don't need a startup console version here */
2208 "changing ThreadLimit to %d from original value of %d "
2209 "not allowed during restart",
2212 }
2213
2215 if (startup) {
2217 "WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
2218 "of %d threads, decreasing to %d. "
2219 "To increase, please see the ThreadLimit directive.",
2221 } else {
2223 "ThreadsPerChild of %d exceeds ThreadLimit "
2224 "of %d, decreasing to match",
2226 }
2228 }
2229 else if (threads_per_child < 1) {
2230 if (startup) {
2232 "WARNING: ThreadsPerChild of %d not allowed, "
2233 "increasing to 1.", threads_per_child);
2234 } else {
2236 "ThreadsPerChild of %d not allowed, increasing to 1",
2238 }
2240 }
2241
2243 if (startup) {
2245 "WARNING: MaxRequestWorkers of %d is less than "
2246 "ThreadsPerChild of %d, increasing to %d. "
2247 "MaxRequestWorkers must be at least as large "
2248 "as the number of threads in a single server.",
2250 } else {
2252 "MaxRequestWorkers of %d is less than ThreadsPerChild "
2253 "of %d, increasing to match",
2255 }
2257 }
2258
2260
2263
2264 if (startup) {
2266 "WARNING: MaxRequestWorkers of %d is not an integer "
2267 "multiple of ThreadsPerChild of %d, decreasing to nearest "
2268 "multiple %d, for a maximum of %d servers.",
2271 } else {
2273 "MaxRequestWorkers of %d is not an integer multiple of "
2274 "ThreadsPerChild of %d, decreasing to nearest "
2275 "multiple %d", max_workers, threads_per_child,
2277 }
2279 }
2280
2282 if (startup) {
2284 "WARNING: MaxRequestWorkers of %d would require %d "
2285 "servers and would exceed ServerLimit of %d, decreasing to %d. "
2286 "To increase, please see the ServerLimit directive.",
2289 } else {
2291 "MaxRequestWorkers of %d would require %d servers and "
2292 "exceed ServerLimit of %d, decreasing to %d",
2295 }
2297 }
2298
2299 /* ap_daemons_to_start > ap_daemons_limit checked in worker_run() */
2300 if (ap_daemons_to_start < 1) {
2301 if (startup) {
2303 "WARNING: StartServers of %d not allowed, "
2304 "increasing to 1.", ap_daemons_to_start);
2305 } else {
2307 "StartServers of %d not allowed, increasing to 1",
2309 }
2311 }
2312
2313 if (min_spare_threads < 1) {
2314 if (startup) {
2316 "WARNING: MinSpareThreads of %d not allowed, "
2317 "increasing to 1 to avoid almost certain server failure. "
2318 "Please read the documentation.", min_spare_threads);
2319 } else {
2321 "MinSpareThreads of %d not allowed, increasing to 1",
2323 }
2325 }
2326
2327 /* max_spare_threads < min_spare_threads + threads_per_child
2328 * checked in worker_run()
2329 */
2330
2331 return OK;
2332}
2333
2335{
2336 /* Our open_logs hook function must run before the core's, or stderr
2337 * will be redirected to a file, and the messages won't print to the
2338 * console.
2339 */
2340 static const char *const aszSucc[] = {"core.c", NULL};
2341 one_process = 0;
2342
2344 /* we need to set the MPM state before other pre-config hooks use MPM query
2345 * to retrieve it, so register as REALLY_FIRST
2346 */
2352}
2353
2354static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
2355 const char *arg)
2356{
2357 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2358 if (err != NULL) {
2359 return err;
2360 }
2361
2363 return NULL;
2364}
2365
2366static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
2367 const char *arg)
2368{
2369 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2370 if (err != NULL) {
2371 return err;
2372 }
2373
2375 return NULL;
2376}
2377
2378static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
2379 const char *arg)
2380{
2381 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2382 if (err != NULL) {
2383 return err;
2384 }
2385
2387 return NULL;
2388}
2389
2390static const char *set_max_workers (cmd_parms *cmd, void *dummy,
2391 const char *arg)
2392{
2393 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2394 if (err != NULL) {
2395 return err;
2396 }
2397 if (!strcasecmp(cmd->cmd->name, "MaxClients")) {
2399 "MaxClients is deprecated, use MaxRequestWorkers "
2400 "instead.");
2401 }
2402 max_workers = atoi(arg);
2403 return NULL;
2404}
2405
2406static const char *set_threads_per_child (cmd_parms *cmd, void *dummy,
2407 const char *arg)
2408{
2409 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2410 if (err != NULL) {
2411 return err;
2412 }
2413
2415 return NULL;
2416}
2417
2418static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
2419{
2420 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2421 if (err != NULL) {
2422 return err;
2423 }
2424
2426 return NULL;
2427}
2428
2429static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg)
2430{
2431 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2432 if (err != NULL) {
2433 return err;
2434 }
2435
2437 return NULL;
2438}
2439
2440static const command_rec worker_cmds[] = {
2443 "Number of child processes launched at server startup"),
2445 "Minimum number of idle threads, to handle request spikes"),
2447 "Maximum number of idle threads"),
2448AP_INIT_TAKE1("MaxRequestWorkers", set_max_workers, NULL, RSRC_CONF,
2449 "Maximum number of threads alive at the same time"),
2451 "Deprecated name of MaxRequestWorkers"),
2453 "Number of threads each child creates"),
2455 "Maximum number of child processes for this run of Apache"),
2457 "Maximum number of worker threads per child process for this run of Apache - Upper limit for ThreadsPerChild"),
2459{ NULL }
2460};
2461
2464 NULL, /* hook to run before apache parses args */
2465 NULL, /* create per-directory config structure */
2466 NULL, /* merge per-directory config structures */
2467 NULL, /* create per-server config structure */
2468 NULL, /* merge per-server config structures */
2469 worker_cmds, /* command apr_table_t */
2470 worker_hooks /* register_hooks */
2471};
2472
Symbol export macros and hook functions.
Apache Listeners Library.
Apache Multi-Processing Module library.
APR File I/O Handling.
APR Poll interface.
APR Portability Routines.
APR Process Locking Routines.
APR Signal Handling.
APR Strings library.
APR Thread Mutex Routines.
APR Thread and Process Library.
APR Standard Headers Support.
void ap_process_connection(conn_rec *c, void *csd)
Definition connection.c:210
void ap_lingering_close(conn_rec *c)
Definition connection.c:149
conn_rec * ap_run_create_connection(apr_pool_t *p, server_rec *server, apr_socket_t *csd, long conn_id, void *sbh, apr_bucket_alloc_t *alloc)
Definition connection.c:41
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
void ap_run_child_init(apr_pool_t *pchild, server_rec *s)
Definition config.c:167
#define AP_DECLARE_MODULE(foo)
void ap_hook_open_logs(ap_HOOK_open_logs_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:163
void ap_hook_check_config(ap_HOOK_check_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:96
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
void * ap_retained_data_create(const char *key, apr_size_t size)
Definition config.c:2527
const char server_rec server_rec ** ps
void * ap_retained_data_get(const char *key)
Definition config.c:2519
void * csd
const char * ap_get_server_built(void)
Definition buildmark.c:26
const char * ap_get_server_description(void)
Definition core.c:3587
#define APEXIT_CHILDSICK
Definition httpd.h:335
#define OK
Definition httpd.h:456
#define DONE
Definition httpd.h:458
#define APEXIT_CHILDFATAL
Definition httpd.h:341
int ap_exists_config_define(const char *name)
Definition core.c:2896
void ap_close_listeners(void)
Definition listen.c:763
#define LISTEN_COMMANDS
Definition ap_listen.h:146
void ap_close_listeners_ex(ap_listen_rec *listeners)
Definition listen.c:778
void ap_listen_pre_config(void)
Definition listen.c:804
apr_status_t ap_duplicate_listeners(apr_pool_t *p, server_rec *s, ap_listen_rec ***buckets, int *num_buckets)
Definition listen.c:669
int ap_setup_listeners(server_rec *s)
Definition listen.c:610
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define APLOG_STARTUP
Definition http_log.h:105
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
void ap_remove_pid(apr_pool_t *p, const char *fname)
Definition log.c:1611
#define APLOG_ALERT
Definition http_log.h:65
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_EMERG
Definition http_log.h:64
#define APLOG_TRACE1
Definition http_log.h:72
void ap_log_mpm_common(server_rec *s)
Definition log.c:1603
void ap_log_pid(apr_pool_t *p, const char *fname)
Definition log.c:1630
#define APLOG_DEBUG
Definition http_log.h:71
void ap_log_command_line(apr_pool_t *p, server_rec *s)
Definition log.c:1575
apr_pool_t * ap_pglobal
Definition config.c:63
server_rec * ap_server_conf
Definition config.c:62
void ap_run_child_status(server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status state)
Definition mpm_common.c:109
void ap_hook_mpm(ap_HOOK_mpm_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:97
@ MPM_CHILD_EXITED
Definition ap_mpm.h:207
@ MPM_CHILD_STARTED
Definition ap_mpm.h:206
@ MPM_CHILD_LOST_SLOT
Definition ap_mpm.h:208
apr_status_t ap_proc_mutex_create(apr_proc_mutex_t **mutex, const char **name, const char *type, const char *instance_id, server_rec *server, apr_pool_t *pool, apr_int32_t options)
Definition util_mutex.c:454
apr_status_t ap_mutex_register(apr_pool_t *pconf, const char *type, const char *default_dir, apr_lockmech_e default_mech, apr_int32_t options)
Definition util_mutex.c:254
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define DEFAULT_MAX_FREE_DAEMON
Definition mpm_default.h:42
#define DEFAULT_MIN_FREE_DAEMON
Definition mpm_default.h:48
#define DEFAULT_START_DAEMON
Definition mpm_default.h:34
#define DEFAULT_THREADS_PER_CHILD
Definition mpm_default.h:52
#define AP_SIG_GRACEFUL_STRING
Definition mpm_common.h:73
void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret, apr_pool_t *p, server_rec *s)
Definition mpm_common.c:181
const char * ap_pid_fname
Definition mpm_common.c:150
apr_status_t ap_mpm_safe_kill(pid_t pid, int sig)
Definition mpm_unix.c:331
#define AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND
Definition mpm_common.h:369
#define AP_ACCEPT_MUTEX_TYPE
Definition mpm_common.h:467
int ap_max_requests_per_child
Definition mpm_common.c:151
#define AP_SIG_GRACEFUL_STOP_STRING
Definition mpm_common.h:82
int ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *old_gen)
Definition mpm_unix.c:92
void ap_run_child_stopping(apr_pool_t *pchild, int graceful)
Definition mpm_common.c:118
void ap_hook_mpm_get_name(ap_HOOK_mpm_get_name_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:136
void ap_relieve_child_processes(ap_reclaim_callback_fn_t *mpm_callback)
Definition mpm_unix.c:286
int ap_graceful_shutdown_timeout
Definition mpm_common.c:154
int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status)
Definition mpm_unix.c:386
void ap_reclaim_child_processes(int terminate, ap_reclaim_callback_fn_t *mpm_callback)
Definition mpm_unix.c:184
apr_status_t ap_fatal_signal_child_setup(server_rec *s)
Definition mpm_unix.c:1011
void ap_hook_mpm_query(ap_HOOK_mpm_query_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:100
void ap_mpm_podx_killpg(ap_pod_t *pod, int num, ap_podx_restart_t graceful)
Definition mpm_unix.c:609
apr_size_t ap_thread_stacksize
Definition mpm_common.c:156
void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen)
Definition mpm_unix.c:82
apr_uint32_t ap_max_mem_free
Definition mpm_common.c:155
apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf)
Definition mpm_unix.c:1044
int ap_mpm_podx_check(ap_pod_t *pod)
Definition mpm_unix.c:540
apr_status_t ap_mpm_podx_signal(ap_pod_t *pod, ap_podx_restart_t graceful)
Definition mpm_unix.c:603
apr_status_t ap_mpm_podx_close(ap_pod_t *pod)
Definition mpm_unix.c:562
int ap_run_drop_privileges(apr_pool_t *pchild, server_rec *s)
Definition mpm_common.c:94
apr_status_t ap_mpm_podx_open(apr_pool_t *p, ap_pod_t **pod)
Definition mpm_unix.c:519
@ AP_MPM_PODX_NORESTART
Definition mpm_common.h:284
@ AP_MPM_PODX_RESTART
Definition mpm_common.h:284
@ AP_MPM_PODX_GRACEFUL
Definition mpm_common.h:284
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_OC_REASON_DEATH
#define APR_STATUS_IS_EINTR(s)
Definition apr_errno.h:1281
#define APR_STATUS_IS_EOF(s)
Definition apr_errno.h:567
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
const char *const const char *const * aszSucc
Definition apr_hooks.h:346
#define APR_HOOK_REALLY_FIRST
Definition apr_hooks.h:299
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define RSRC_CONF
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define MPM20_MODULE_STUFF
#define AP_DEBUG_ASSERT(exp)
Definition httpd.h:2283
void * ap_calloc(size_t nelem, size_t size) __attribute__((malloc))
Definition util.c:3160
#define ap_assert(exp)
Definition httpd.h:2271
void * ap_malloc(size_t size) __attribute__((malloc))
Definition util.c:3152
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_array_header_t ** result
int strcasecmp(const char *a, const char *b)
apr_socket_t * sock
apr_interval_time_t apr_pollcb_cb_t func
Definition apr_poll.h:422
@ APR_POLL_SOCKET
Definition apr_poll.h:93
apr_abortfunc_t apr_allocator_t * allocator
Definition apr_pools.h:208
const char apr_status_t(*) apr_pool_t *poo __attribute__)((nonnull(2, 4)))
Definition apr_pools.h:567
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
@ APR_LOCK_DEFAULT
#define apr_signal(a, b)
Definition apr_signal.h:71
void apr_skiplistnode ** iter
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
int sig
int apr_exit_why_e * exitwhy
apr_cmdtype_e cmd
#define APR_PROC_CHECK_SIGNALED(x)
#define APR_PROC_DETACH_DAEMONIZE
#define APR_PROC_DETACH_FOREGROUND
apr_exit_why_e
int int status
#define apr_time_from_msec(msec)
Definition apr_time.h:75
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_from_sec(sec)
Definition apr_time.h:78
#define APR_POLLSET_NOCOPY
Definition apr_poll.h:65
#define APR_POLLSET_WAKEABLE
Definition apr_poll.h:68
#define APR_POLLIN
Definition apr_poll.h:49
#define AP_MPMQ_IS_FORKED
Definition ap_mpm.h:154
#define AP_MPMQ_MPM_STATE
Definition ap_mpm.h:174
#define AP_MPMQ_MAX_DAEMON_USED
Definition ap_mpm.h:150
#define AP_MPMQ_MAX_SPARE_DAEMONS
Definition ap_mpm.h:166
#define AP_MPMQ_MIN_SPARE_THREADS
Definition ap_mpm.h:164
#define AP_MPMQ_HARD_LIMIT_THREADS
Definition ap_mpm.h:158
#define AP_MPMQ_IS_THREADED
Definition ap_mpm.h:152
#define AP_MPMQ_MAX_THREADS
Definition ap_mpm.h:160
#define AP_MPMQ_MAX_REQUESTS_DAEMON
Definition ap_mpm.h:170
#define AP_MPMQ_MAX_SPARE_THREADS
Definition ap_mpm.h:168
#define AP_MPMQ_GENERATION
Definition ap_mpm.h:178
#define AP_MPMQ_MAX_DAEMONS
Definition ap_mpm.h:172
#define AP_MPMQ_HARD_LIMIT_DAEMONS
Definition ap_mpm.h:156
#define AP_MPMQ_MIN_SPARE_DAEMONS
Definition ap_mpm.h:162
#define AP_MPMQ_STARTING
Definition ap_mpm.h:140
#define AP_MPMQ_RUNNING
Definition ap_mpm.h:141
#define AP_MPMQ_STOPPING
Definition ap_mpm.h:142
#define RAISE_SIGSTOP(x)
Definition httpd.h:2312
#define AP_MPMQ_DYNAMIC
Definition ap_mpm.h:131
#define AP_MPMQ_STATIC
Definition ap_mpm.h:128
Apache Configuration.
Apache connection library.
CORE HTTP Daemon.
Apache Logging library.
Command line options.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static unsigned long num_buckets
#define debug(stmt)
Definition mod_macro.c:43
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
Multi-Processing Modules functions.
fd queue declarations
static int idle_spawn_rate
static int child_slot
apr_status_t apr_proc_detach(int daemonize)
Definition procsup.c:19
apr_status_t apr_thread_exit(apr_thread_t *thd, apr_status_t retval)
Definition thread.c:157
apr_os_thread_t apr_os_thread_current()
Definition thread.c:142
apr_status_t apr_thread_join(apr_status_t *retval, apr_thread_t *thd)
Definition thread.c:166
apr_status_t apr_threadattr_detach_set(apr_threadattr_t *attr, apr_int32_t on)
Definition thread.c:41
apr_status_t apr_threadattr_create(apr_threadattr_t **new, apr_pool_t *pool)
Definition thread.c:24
static int my_child_num
Definition prefork.c:154
Apache scoreboard library.
void ap_create_sb_handle(ap_sb_handle_t **new_sbh, apr_pool_t *p, int child_num, int thread_num)
Definition scoreboard.c:432
int ap_run_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type)
Definition scoreboard.c:102
#define SERVER_STARTING
Definition scoreboard.h:57
int ap_generation_t
Definition scoreboard.h:78
scoreboard * ap_scoreboard_image
Definition scoreboard.c:44
int ap_extended_status
Definition scoreboard.c:61
apr_status_t ap_reopen_scoreboard(apr_pool_t *p, apr_shm_t **shm, int detached)
Definition scoreboard.c:263
@ SB_SHARED
Definition scoreboard.h:85
#define SERVER_GRACEFUL
Definition scoreboard.h:65
#define SERVER_DEAD
Definition scoreboard.h:56
int ap_update_child_status_from_indexes(int child_num, int thread_num, int status, request_rec *r)
Definition scoreboard.c:575
int ap_find_child_by_pid(apr_proc_t *pid)
Definition scoreboard.c:409
#define SERVER_READY
Definition scoreboard.h:58
process_score * ap_get_scoreboard_process(int x)
Definition scoreboard.c:702
Apache's listeners record.
Definition ap_listen.h:47
ap_listen_rec * next
Definition ap_listen.h:51
void * client_data
Definition apr_poll.h:114
apr_int16_t reqevents
Definition apr_poll.h:111
apr_datatype_e desc_type
Definition apr_poll.h:110
apr_descriptor desc
Definition apr_poll.h:113
Structure to store things which are per connection.
Definition httpd.h:1152
ap_generation_t running_generation
Definition scoreboard.h:126
int sd
Definition worker.c:188
int pid
Definition worker.c:186
int tid
Definition worker.c:187
ap_generation_t generation
Definition scoreboard.h:139
worker_score ** servers
Definition scoreboard.h:163
process_score * parent
Definition scoreboard.h:162
global_score * global
Definition scoreboard.h:161
A structure to store information for each virtual server.
Definition httpd.h:1322
apr_threadattr_t * threadattr
Definition event.c:349
apr_thread_t ** threads
Definition event.c:346
int child_num_arg
Definition event.c:348
apr_thread_t * listener
Definition event.c:347
ap_listen_rec * listeners
Definition worker.c:176
ap_pod_t * pod
Definition worker.c:175
apr_proc_mutex_t * mutex
Definition worker.c:177
ap_unixd_mpm_retained_data * mpm
Definition worker.c:146
int hold_off_on_exponential_spawning
Definition worker.c:170
int near_maxclients_reported
Definition worker.c:152
unsigned char status
Definition scoreboard.h:102
ap_generation_t generation
Definition scoreboard.h:101
apr_socket_t * s
Definition apr_poll.h:101
apr_status_t apr_socket_close(apr_socket_t *thesocket)
Definition sockets.c:211
Apache Mutex support library.
Worker MPM defaults.
static void perform_idle_server_maintenance(int child_bucket)
Definition worker.c:1400
#define DEFAULT_SERVER_LIMIT
Definition worker.c:87
static int one_process
Definition worker.c:216
static void *APR_THREAD_FUNC listener_thread(apr_thread_t *thd, void *dummy)
Definition worker.c:552
static int had_healthy_child
Definition worker.c:127
static int server_limit
Definition worker.c:125
#define ST_INIT
Definition worker.c:305
static void join_start_thread(apr_thread_t *start_thread_id)
Definition worker.c:1098
static void startup_children(int number_to_start)
Definition worker.c:1385
static apr_pool_t * pruntime
Definition worker.c:224
static apr_pollset_t * worker_pollset
Definition worker.c:138
#define MAX_SPAWN_RATE
Definition worker.c:168
static void process_socket(apr_thread_t *thd, apr_pool_t *p, apr_socket_t *sock, int my_child_num, int my_thread_num, apr_bucket_alloc_t *bucket_alloc)
Definition worker.c:477
static void *APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void *dummy)
Definition worker.c:742
static int start_thread_may_exit
Definition worker.c:130
static worker_retained_data * retained
Definition worker.c:172
static apr_socket_t ** worker_sockets
Definition worker.c:260
static void unblock_signal(int sig)
Definition worker.c:509
static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
Definition worker.c:1960
static apr_pool_t * pchild
Definition worker.c:223
static void server_main_loop(int remaining_children_to_start)
Definition worker.c:1607
static worker_child_bucket * my_bucket
Definition worker.c:180
static int max_spare_threads
Definition worker.c:122
static void just_die(int sig)
Definition worker.c:458
static void clean_child_exit(int code) __attribute__((noreturn))
Definition worker.c:440
static void accept_mutex_error(const char *func, apr_status_t rv, int process_slot)
Definition worker.c:529
static int child_fatal
Definition worker.c:467
#define ST_UNGRACEFUL
Definition worker.c:307
static int min_spare_threads
Definition worker.c:121
static int worker_query(int query_code, int *result, apr_status_t *rv)
Definition worker.c:337
static void worker_note_child_started(int slot, pid_t pid)
Definition worker.c:404
static apr_pool_t * pconf
Definition worker.c:222
static void join_workers(apr_thread_t *listener, apr_thread_t **threads, int mode)
Definition worker.c:1035
#define MAX_SERVER_LIMIT
Definition worker.c:94
static void child_main(int child_num_arg, int child_bucket)
Definition worker.c:1114
static void *APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy)
Definition worker.c:955
#define LISTENER_SIGNAL
Definition worker.c:243
static void signal_threads(int mode)
Definition worker.c:311
static void worker_hooks(apr_pool_t *p)
Definition worker.c:2334
static void worker_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
Definition worker.c:390
#define DEFAULT_THREAD_LIMIT
Definition worker.c:105
static int listener_may_exit
Definition worker.c:131
static void dummy_signal_handler(int sig)
Definition worker.c:522
static const char * set_max_workers(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2390
static const char * set_server_limit(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2418
static const char * set_min_spare_threads(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2366
static int max_workers
Definition worker.c:124
static const char * set_thread_limit(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2429
static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
Definition worker.c:1748
#define MPM_CHILD_PID(i)
Definition worker.c:182
static pid_t parent_pid
Definition worker.c:228
static int ap_daemons_limit
Definition worker.c:123
static fd_queue_t * worker_queue
Definition worker.c:136
static const char * set_max_spare_threads(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2378
static const char * worker_get_name(void)
Definition worker.c:433
#define WORKER_SIGNAL
Definition worker.c:256
static void worker_note_child_lost_slot(int slot, pid_t newpid)
Definition worker.c:412
#define MAX_THREAD_LIMIT
Definition worker.c:112
#define ST_GRACEFUL
Definition worker.c:306
static pid_t ap_my_pid
Definition worker.c:226
static int num_listensocks
Definition worker.c:134
static int listener_is_wakeable
Definition worker.c:132
static fd_queue_info_t * worker_queue_info
Definition worker.c:137
static apr_os_thread_t * listener_os_thread
Definition worker.c:229
static const command_rec worker_cmds[]
Definition worker.c:2440
static int thread_limit
Definition worker.c:126
static int make_child(server_rec *s, int slot, int bucket)
Definition worker.c:1309
static const char * set_threads_per_child(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2406
static const char * set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
Definition worker.c:2354
#define ID_FROM_CHILD_THREAD(c, t)
Definition worker.c:201
static void setup_threads_runtime(void)
Definition worker.c:867
static int check_signal(int signum)
Definition worker.c:835
static void close_worker_sockets(void)
Definition worker.c:262
static int worker_check_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
Definition worker.c:2120
static volatile int dying
Definition worker.c:128
static void create_listener_thread(thread_starter *ts)
Definition worker.c:845
static worker_child_bucket * all_buckets
Definition worker.c:179
static int requests_this_child
Definition worker.c:133
static int ap_daemons_to_start
Definition worker.c:120
static int workers_may_exit
Definition worker.c:129
static int resource_shortage
Definition worker.c:135
static int threads_per_child
Definition worker.c:119
static void wakeup_listener(void)
Definition worker.c:273
#define SAFE_ACCEPT(stmt)
Definition worker.c:234
static void check_infinite_requests(void)
Definition worker.c:499
static int terminate_mode
Definition worker.c:309
static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
Definition worker.c:2055