]> git.pld-linux.org Git - packages/apache.git/blame - apache-mpm-itk.patch
- up to 2.4.59
[packages/apache.git] / apache-mpm-itk.patch
CommitLineData
7dda4a20
JR
1http://mpm-itk.sesse.net/apache2.2-mpm-itk-20090414-00.patch
2
3unchanged:
4--- httpd-2.2.11/server/mpm/experimental/itk/Makefile.in 2009-03-17 21:38:54.000000000 +0100
5+++ httpd-2.2.11/server/mpm/experimental/itk/Makefile.in 2009-03-17 21:39:03.000000000 +0100
6@@ -0,0 +1,5 @@
7+
8+LTLIBRARY_NAME = libitk.la
9+LTLIBRARY_SOURCES = itk.c
10+
11+include $(top_srcdir)/build/ltlib.mk
12unchanged:
13--- httpd-2.2.11/server/mpm/experimental/itk/config.m4 2009-03-17 21:38:53.000000000 +0100
14+++ httpd-2.2.11/server/mpm/experimental/itk/config.m4 2009-03-17 21:39:03.000000000 +0100
15@@ -0,0 +1,3 @@
16+if test "$MPM_NAME" = "itk" ; then
17+ APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
18+fi
19diff -u httpd-2.2.11/server/mpm/experimental/itk/itk.c httpd-2.2.11/server/mpm/experimental/itk/itk.c
20--- httpd-2.2.11/server/mpm/experimental/itk/itk.c 2009-04-14 23:29:16.000000000 +0200
21+++ httpd-2.2.11/server/mpm/experimental/itk/itk.c 2009-04-14 23:31:05.000000000 +0200
22@@ -0,0 +1,1740 @@
23+/* Licensed to the Apache Software Foundation (ASF) under one or more
24+ * contributor license agreements. See the NOTICE file distributed with
25+ * this work for additional information regarding copyright ownership.
26+ * The ASF licenses this file to You under the Apache License, Version 2.0
27+ * (the "License"); you may not use this file except in compliance with
28+ * the License. You may obtain a copy of the License at
29+ *
30+ * http://www.apache.org/licenses/LICENSE-2.0
31+ *
32+ * Unless required by applicable law or agreed to in writing, software
33+ * distributed under the License is distributed on an "AS IS" BASIS,
34+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35+ * See the License for the specific language governing permissions and
36+ * limitations under the License.
37+ *
38+ * Portions copyright 2005-2009 Steinar H. Gunderson <sgunderson@bigfoot.com>.
39+ * Licensed under the same terms as the rest of Apache.
40+ *
41+ * Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>.
42+ * Licensed under the same terms as the rest of Apache.
43+ */
44+
45+#include "apr.h"
46+#include "apr_portable.h"
47+#include "apr_strings.h"
48+#include "apr_thread_proc.h"
49+#include "apr_signal.h"
50+
51+# define _DBG(text,par...) \
52+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \
53+ "(itkmpm: pid=%d uid=%d, gid=%d) %s(): " text, \
54+ getpid(), getuid(), getgid(), __FUNCTION__, par)
55+
56+#define APR_WANT_STDIO
57+#define APR_WANT_STRFUNC
58+#include "apr_want.h"
59+
60+#if APR_HAVE_UNISTD_H
61+#include <unistd.h>
62+#endif
63+#if APR_HAVE_SYS_TYPES_H
64+#include <sys/types.h>
65+#endif
66+
67+#define CORE_PRIVATE
68+
69+#include "ap_config.h"
70+#include "httpd.h"
71+#include "mpm_default.h"
72+#include "http_main.h"
73+#include "http_log.h"
74+#include "http_config.h"
75+#include "http_core.h" /* for get_remote_host */
76+#include "http_connection.h"
77+#include "http_request.h" /* for ap_hook_post_perdir_config */
78+#include "scoreboard.h"
79+#include "ap_mpm.h"
80+#include "unixd.h"
81+#include "mpm_common.h"
82+#include "ap_listen.h"
83+#include "ap_mmn.h"
84+#include "apr_poll.h"
85+
86+#ifdef HAVE_BSTRING_H
87+#include <bstring.h> /* for IRIX, FD_SET calls bzero() */
88+#endif
89+#ifdef HAVE_TIME_H
90+#include <time.h>
91+#endif
92+#ifdef HAVE_SYS_PROCESSOR_H
93+#include <sys/processor.h> /* for bindprocessor() */
94+#endif
95+
96+#if HAVE_LIBCAP
97+#include <sys/capability.h>
98+#endif
99+
100+#include <signal.h>
101+#include <sys/times.h>
102+
103+/* Limit on the total --- clients will be locked out if more servers than
104+ * this are needed. It is intended solely to keep the server from crashing
105+ * when things get out of hand.
106+ *
107+ * We keep a hard maximum number of servers, for two reasons --- first off,
108+ * in case something goes seriously wrong, we want to stop the fork bomb
109+ * short of actually crashing the machine we're running on by filling some
110+ * kernel table. Secondly, it keeps the size of the scoreboard file small
111+ * enough that we can read the whole thing without worrying too much about
112+ * the overhead.
113+ */
114+#ifndef DEFAULT_SERVER_LIMIT
115+#define DEFAULT_SERVER_LIMIT 256
116+#endif
117+
118+/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
119+ * some sort of compile-time limit to help catch typos.
120+ */
121+#ifndef MAX_SERVER_LIMIT
122+#define MAX_SERVER_LIMIT 200000
123+#endif
124+
125+#ifndef HARD_THREAD_LIMIT
126+#define HARD_THREAD_LIMIT 1
127+#endif
128+
129+/* config globals */
130+
131+int ap_threads_per_child=0; /* Worker threads per child */
132+static apr_proc_mutex_t *accept_mutex;
133+static int ap_daemons_to_start=0;
134+static int ap_daemons_min_free=0;
135+static int ap_daemons_max_free=0;
136+static int ap_daemons_limit=0; /* MaxClients */
137+static int server_limit = DEFAULT_SERVER_LIMIT;
138+static int first_server_limit = 0;
139+static int changed_limit_at_restart;
140+static int mpm_state = AP_MPMQ_STARTING;
141+static ap_pod_t *pod;
142+
143+/*
144+ * The max child slot ever assigned, preserved across restarts. Necessary
145+ * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
146+ * use this value to optimize routines that have to scan the entire scoreboard.
147+ */
148+int ap_max_daemons_limit = -1;
149+server_rec *ap_server_conf;
150+
151+/* one_process --- debugging mode variable; can be set from the command line
152+ * with the -X flag. If set, this gets you the child_main loop running
153+ * in the process which originally started up (no detach, no make_child),
154+ * which is a pretty nice debugging environment. (You'll get a SIGHUP
155+ * early in standalone_main; just continue through. This is the server
156+ * trying to kill off any child processes which it might have lying
157+ * around --- Apache doesn't keep track of their pids, it just sends
158+ * SIGHUP to the process group, ignoring it in the root process.
159+ * Continue through and you'll be fine.).
160+ */
161+
162+static int one_process = 0;
163+
164+static apr_pool_t *pconf; /* Pool for config stuff */
165+static apr_pool_t *pchild; /* Pool for httpd child stuff */
166+
167+static pid_t ap_my_pid; /* it seems silly to call getpid all the time */
168+static pid_t parent_pid;
169+#ifndef MULTITHREAD
170+static int my_child_num;
171+#endif
172+ap_generation_t volatile ap_my_generation=0;
173+
174+#ifdef TPF
175+int tpf_child = 0;
176+char tpf_server_name[INETD_SERVNAME_LENGTH+1];
177+#endif /* TPF */
178+
179+static volatile int die_now = 0;
180+
181+#define UNSET_NICE_VALUE 100
182+
183+typedef struct
184+{
185+ uid_t uid;
186+ gid_t gid;
187+ char *username;
188+ int nice_value;
189+} itk_per_dir_conf;
190+
191+typedef struct
192+{
193+ int max_clients_vhost;
194+} itk_server_conf;
195+
196+module AP_MODULE_DECLARE_DATA mpm_itk_module;
197+
198+#ifdef GPROF
199+/*
200+ * change directory for gprof to plop the gmon.out file
201+ * configure in httpd.conf:
202+ * GprofDir $RuntimeDir/ -> $ServerRoot/$RuntimeDir/gmon.out
203+ * GprofDir $RuntimeDir/% -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out
204+ */
205+static void chdir_for_gprof(void)
206+{
207+ core_server_config *sconf =
208+ ap_get_module_config(ap_server_conf->module_config, &core_module);
209+ char *dir = sconf->gprof_dir;
210+ const char *use_dir;
211+
212+ if(dir) {
213+ apr_status_t res;
214+ char *buf = NULL ;
215+ int len = strlen(sconf->gprof_dir) - 1;
216+ if(*(dir + len) == '%') {
217+ dir[len] = '\0';
218+ buf = ap_append_pid(pconf, dir, "gprof.");
219+ }
220+ use_dir = ap_server_root_relative(pconf, buf ? buf : dir);
221+ res = apr_dir_make(use_dir,
222+ APR_UREAD | APR_UWRITE | APR_UEXECUTE |
223+ APR_GREAD | APR_GEXECUTE |
224+ APR_WREAD | APR_WEXECUTE, pconf);
225+ if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) {
226+ ap_log_error(APLOG_MARK, APLOG_ERR, res, ap_server_conf,
227+ "gprof: error creating directory %s", dir);
228+ }
229+ }
230+ else {
231+ use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR);
232+ }
233+
234+ chdir(use_dir);
235+}
236+#else
237+#define chdir_for_gprof()
238+#endif
239+
240+/* XXX - I don't know if TPF will ever use this module or not, so leave
241+ * the ap_check_signals calls in but disable them - manoj */
242+#define ap_check_signals()
243+
244+/* a clean exit from a child with proper cleanup */
245+static void clean_child_exit(int code) __attribute__ ((noreturn));
246+static void clean_child_exit(int code)
247+{
248+ mpm_state = AP_MPMQ_STOPPING;
249+
250+ if (pchild) {
251+ apr_pool_destroy(pchild);
252+ }
253+ ap_mpm_pod_close(pod);
254+ chdir_for_gprof();
255+ exit(code);
256+}
257+
258+static void accept_mutex_on(void)
259+{
260+ apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
261+ if (rv != APR_SUCCESS) {
262+ const char *msg = "couldn't grab the accept mutex";
263+
264+ if (ap_my_generation !=
265+ ap_scoreboard_image->global->running_generation) {
266+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, "%s", msg);
267+ clean_child_exit(0);
268+ }
269+ else {
270+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "%s", msg);
271+ exit(APEXIT_CHILDFATAL);
272+ }
273+ }
274+}
275+
276+static void accept_mutex_off(void)
277+{
278+ apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
279+ if (rv != APR_SUCCESS) {
280+ const char *msg = "couldn't release the accept mutex";
281+
282+ if (ap_my_generation !=
283+ ap_scoreboard_image->global->running_generation) {
284+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, "%s", msg);
285+ /* don't exit here... we have a connection to
286+ * process, after which point we'll see that the
287+ * generation changed and we'll exit cleanly
288+ */
289+ }
290+ else {
291+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "%s", msg);
292+ exit(APEXIT_CHILDFATAL);
293+ }
294+ }
295+}
296+
297+/* On some architectures it's safe to do unserialized accept()s in the single
298+ * Listen case. But it's never safe to do it in the case where there's
299+ * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
300+ * when it's safe in the single Listen case.
301+ */
302+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
303+#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
304+#else
305+#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
306+#endif
307+
308+AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
309+{
310+ switch(query_code){
311+ case AP_MPMQ_MAX_DAEMON_USED:
312+ *result = ap_daemons_limit;
313+ return APR_SUCCESS;
314+ case AP_MPMQ_IS_THREADED:
315+ *result = AP_MPMQ_NOT_SUPPORTED;
316+ return APR_SUCCESS;
317+ case AP_MPMQ_IS_FORKED:
318+ *result = AP_MPMQ_DYNAMIC;
319+ return APR_SUCCESS;
320+ case AP_MPMQ_HARD_LIMIT_DAEMONS:
321+ *result = server_limit;
322+ return APR_SUCCESS;
323+ case AP_MPMQ_HARD_LIMIT_THREADS:
324+ *result = HARD_THREAD_LIMIT;
325+ return APR_SUCCESS;
326+ case AP_MPMQ_MAX_THREADS:
327+ *result = 0;
328+ return APR_SUCCESS;
329+ case AP_MPMQ_MIN_SPARE_DAEMONS:
330+ *result = ap_daemons_min_free;
331+ return APR_SUCCESS;
332+ case AP_MPMQ_MIN_SPARE_THREADS:
333+ *result = 0;
334+ return APR_SUCCESS;
335+ case AP_MPMQ_MAX_SPARE_DAEMONS:
336+ *result = ap_daemons_max_free;
337+ return APR_SUCCESS;
338+ case AP_MPMQ_MAX_SPARE_THREADS:
339+ *result = 0;
340+ return APR_SUCCESS;
341+ case AP_MPMQ_MAX_REQUESTS_DAEMON:
342+ *result = ap_max_requests_per_child;
343+ return APR_SUCCESS;
344+ case AP_MPMQ_MAX_DAEMONS:
345+ *result = server_limit;
346+ return APR_SUCCESS;
347+ case AP_MPMQ_MPM_STATE:
348+ *result = mpm_state;
349+ return APR_SUCCESS;
350+ }
351+ return APR_ENOTIMPL;
352+}
353+
354+#if defined(NEED_WAITPID)
355+/*
356+ Systems without a real waitpid sometimes lose a child's exit while waiting
357+ for another. Search through the scoreboard for missing children.
358+ */
359+int reap_children(int *exitcode, apr_exit_why_e *status)
360+{
361+ int n, pid;
362+
363+ for (n = 0; n < ap_max_daemons_limit; ++n) {
364+ if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
365+ kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
366+ ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL);
367+ /* just mark it as having a successful exit status */
368+ *status = APR_PROC_EXIT;
369+ *exitcode = 0;
370+ return(pid);
371+ }
372+ }
373+ return 0;
374+}
375+#endif
376+
377+/*****************************************************************
378+ * Connection structures and accounting...
379+ */
380+
381+static void just_die(int sig)
382+{
383+ clean_child_exit(0);
384+}
385+
386+static void stop_listening(int sig)
387+{
388+ ap_close_listeners();
389+
390+ /* For a graceful stop, we want the child to exit when done */
391+ die_now = 1;
392+}
393+
394+/* volatile just in case */
395+static int volatile shutdown_pending;
396+static int volatile restart_pending;
397+static int volatile is_graceful;
398+
399+static void sig_term(int sig)
400+{
401+ if (shutdown_pending == 1) {
402+ /* Um, is this _probably_ not an error, if the user has
403+ * tried to do a shutdown twice quickly, so we won't
404+ * worry about reporting it.
405+ */
406+ return;
407+ }
408+ shutdown_pending = 1;
409+ is_graceful = (sig == AP_SIG_GRACEFUL_STOP);
410+}
411+
412+/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL
413+ * in the parent process, unless running in ONE_PROCESS mode
414+ */
415+static void restart(int sig)
416+{
417+ if (restart_pending == 1) {
418+ /* Probably not an error - don't bother reporting it */
419+ return;
420+ }
421+ restart_pending = 1;
422+ is_graceful = (sig == AP_SIG_GRACEFUL);
423+}
424+
425+static void set_signals(void)
426+{
427+#ifndef NO_USE_SIGACTION
428+ struct sigaction sa;
429+#endif
430+
431+ if (!one_process) {
432+ ap_fatal_signal_setup(ap_server_conf, pconf);
433+ }
434+
435+#ifndef NO_USE_SIGACTION
436+ sigemptyset(&sa.sa_mask);
437+ sa.sa_flags = 0;
438+
439+ sa.sa_handler = sig_term;
440+ if (sigaction(SIGTERM, &sa, NULL) < 0)
441+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
442+#ifdef AP_SIG_GRACEFUL_STOP
443+ if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
444+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
445+ "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
446+#endif
447+#ifdef SIGINT
448+ if (sigaction(SIGINT, &sa, NULL) < 0)
449+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
450+#endif
451+#ifdef SIGXCPU
452+ sa.sa_handler = SIG_DFL;
453+ if (sigaction(SIGXCPU, &sa, NULL) < 0)
454+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");
455+#endif
456+#ifdef SIGXFSZ
457+ sa.sa_handler = SIG_DFL;
458+ if (sigaction(SIGXFSZ, &sa, NULL) < 0)
459+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");
460+#endif
461+#ifdef SIGPIPE
462+ sa.sa_handler = SIG_IGN;
463+ if (sigaction(SIGPIPE, &sa, NULL) < 0)
464+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");
465+#endif
466+
467+ /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
468+ * processing one
469+ */
470+ sigaddset(&sa.sa_mask, SIGHUP);
471+ sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
472+ sa.sa_handler = restart;
473+ if (sigaction(SIGHUP, &sa, NULL) < 0)
474+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
475+ if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
476+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
477+#else
478+ if (!one_process) {
479+#ifdef SIGXCPU
480+ apr_signal(SIGXCPU, SIG_DFL);
481+#endif /* SIGXCPU */
482+#ifdef SIGXFSZ
483+ apr_signal(SIGXFSZ, SIG_DFL);
484+#endif /* SIGXFSZ */
485+ }
486+
487+ apr_signal(SIGTERM, sig_term);
488+#ifdef SIGHUP
489+ apr_signal(SIGHUP, restart);
490+#endif /* SIGHUP */
491+#ifdef AP_SIG_GRACEFUL
492+ apr_signal(AP_SIG_GRACEFUL, restart);
493+#endif /* AP_SIG_GRACEFUL */
494+#ifdef AP_SIG_GRACEFUL_STOP
495+ apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
496+#endif /* AP_SIG_GRACEFUL */
497+#ifdef SIGPIPE
498+ apr_signal(SIGPIPE, SIG_IGN);
499+#endif /* SIGPIPE */
500+
501+#endif
502+}
503+
504+/*****************************************************************
505+ * Child process main loop.
506+ * The following vars are static to avoid getting clobbered by longjmp();
507+ * they are really private to child_main.
508+ */
509+
510+static int requests_this_child;
511+static int num_listensocks = 0;
512+
513+
514+int ap_graceful_stop_signalled(void)
515+{
516+ /* not ever called anymore... */
517+ return 0;
518+}
519+
520+
521+static void child_main(int child_num_arg)
522+{
523+ apr_pool_t *ptrans;
524+ apr_allocator_t *allocator;
525+ apr_status_t status;
526+ int i;
527+ ap_listen_rec *lr;
528+ apr_pollset_t *pollset;
529+ ap_sb_handle_t *sbh;
530+ apr_bucket_alloc_t *bucket_alloc;
531+ int last_poll_idx = 0;
532+
533+#if HAVE_LIBCAP
534+ cap_t caps;
535+ cap_value_t suidcaps[] = {
536+ CAP_SETUID,
537+ CAP_SETGID,
538+ CAP_DAC_READ_SEARCH,
539+ CAP_SYS_NICE,
540+ };
541+#endif
542+
543+ mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
544+ * child initializes
545+ */
546+
547+ my_child_num = child_num_arg;
548+ ap_my_pid = getpid();
549+ requests_this_child = 0;
550+
551+ ap_fatal_signal_child_setup(ap_server_conf);
552+
553+ /* Get a sub context for global allocations in this child, so that
554+ * we can have cleanups occur when the child exits.
555+ */
556+ apr_allocator_create(&allocator);
557+ apr_allocator_max_free_set(allocator, ap_max_mem_free);
558+ apr_pool_create_ex(&pchild, pconf, NULL, allocator);
559+ apr_allocator_owner_set(allocator, pchild);
560+
561+ apr_pool_create(&ptrans, pchild);
562+ apr_pool_tag(ptrans, "transaction");
563+
564+ /* needs to be done before we switch UIDs so we have permissions */
565+ ap_reopen_scoreboard(pchild, NULL, 0);
566+ status = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild);
567+ if (status != APR_SUCCESS) {
568+ ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
569+ "Couldn't initialize cross-process lock in child "
570+ "(%s) (%d)", ap_lock_fname, ap_accept_lock_mech);
571+ clean_child_exit(APEXIT_CHILDFATAL);
572+ }
573+
574+ ap_run_child_init(pchild, ap_server_conf);
575+
576+ ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
577+
578+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
579+
580+ /* Set up the pollfd array */
581+ /* ### check the status */
582+ (void) apr_pollset_create(&pollset, num_listensocks, pchild, 0);
583+
584+ for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
585+ apr_pollfd_t pfd = { 0 };
586+
587+ pfd.desc_type = APR_POLL_SOCKET;
588+ pfd.desc.s = lr->sd;
589+ pfd.reqevents = APR_POLLIN;
590+ pfd.client_data = lr;
591+
592+ /* ### check the status */
593+ (void) apr_pollset_add(pollset, &pfd);
594+ }
595+
596+#if HAVE_LIBCAP
597+ /* Drop as many privileges as we can. We'll still
598+ * access files with uid=0, and we can setuid() to anything, but
599+ * at least there's tons of other evilness (like loading kernel
600+ * modules) we can't do directly. (The setuid() capability will
601+ * go away automatically when we setuid() or exec() -- the former
602+ * is likely to come first.)
603+ */
604+ caps = cap_init();
605+ cap_clear(caps);
606+ cap_set_flag(caps, CAP_PERMITTED, sizeof(suidcaps)/sizeof(cap_value_t), suidcaps, CAP_SET);
607+ cap_set_flag(caps, CAP_EFFECTIVE, sizeof(suidcaps)/sizeof(cap_value_t), suidcaps, CAP_SET);
608+ cap_set_proc(caps);
609+ cap_free(caps);
610+#endif
611+
612+ mpm_state = AP_MPMQ_RUNNING;
613+
614+ bucket_alloc = apr_bucket_alloc_create(pchild);
615+
616+ /* die_now is set when AP_SIG_GRACEFUL is received in the child;
617+ * shutdown_pending is set when SIGTERM is received when running
618+ * in single process mode. */
619+ while (!die_now && !shutdown_pending) {
620+ conn_rec *current_conn;
621+ void *csd;
622+
623+ /*
624+ * (Re)initialize this child to a pre-connection state.
625+ */
626+
627+ apr_pool_clear(ptrans);
628+
629+ if ((ap_max_requests_per_child > 0
630+ && requests_this_child++ >= ap_max_requests_per_child)) {
631+ clean_child_exit(0);
632+ }
633+
634+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
635+
636+ /*
637+ * Wait for an acceptable connection to arrive.
638+ */
639+
640+ /* Lock around "accept", if necessary */
641+ SAFE_ACCEPT(accept_mutex_on());
642+
643+ if (num_listensocks == 1) {
644+ /* There is only one listener record, so refer to that one. */
645+ lr = ap_listeners;
646+ }
647+ else {
648+ /* multiple listening sockets - need to poll */
649+ for (;;) {
650+ apr_int32_t numdesc;
651+ const apr_pollfd_t *pdesc;
652+
653+ /* timeout == -1 == wait forever */
654+ status = apr_pollset_poll(pollset, -1, &numdesc, &pdesc);
655+ if (status != APR_SUCCESS) {
656+ if (APR_STATUS_IS_EINTR(status)) {
657+ if (one_process && shutdown_pending) {
658+ return;
659+ }
660+ else if (die_now) {
661+ /* In graceful stop/restart; drop the mutex
662+ * and terminate the child. */
663+ SAFE_ACCEPT(accept_mutex_off());
664+ clean_child_exit(0);
665+ }
666+ continue;
667+ }
668+ /* Single Unix documents select as returning errnos
669+ * EBADF, EINTR, and EINVAL... and in none of those
670+ * cases does it make sense to continue. In fact
671+ * on Linux 2.0.x we seem to end up with EFAULT
672+ * occasionally, and we'd loop forever due to it.
673+ */
674+ ap_log_error(APLOG_MARK, APLOG_ERR, status,
675+ ap_server_conf, "apr_pollset_poll: (listen)");
676+ SAFE_ACCEPT(accept_mutex_off());
677+ clean_child_exit(1);
678+ }
679+
680+ /* We can always use pdesc[0], but sockets at position N
681+ * could end up completely starved of attention in a very
682+ * busy server. Therefore, we round-robin across the
683+ * returned set of descriptors. While it is possible that
684+ * the returned set of descriptors might flip around and
685+ * continue to starve some sockets, we happen to know the
686+ * internal pollset implementation retains ordering
687+ * stability of the sockets. Thus, the round-robin should
688+ * ensure that a socket will eventually be serviced.
689+ */
690+ if (last_poll_idx >= numdesc)
691+ last_poll_idx = 0;
692+
693+ /* Grab a listener record from the client_data of the poll
694+ * descriptor, and advance our saved index to round-robin
695+ * the next fetch.
696+ *
697+ * ### hmm... this descriptor might have POLLERR rather
698+ * ### than POLLIN
699+ */
700+ lr = pdesc[last_poll_idx++].client_data;
701+ goto got_fd;
702+ }
703+ }
704+ got_fd:
705+ /* if we accept() something we don't want to die, so we have to
706+ * defer the exit
707+ */
708+ status = lr->accept_func(&csd, lr, ptrans);
709+
710+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
711+
712+ if (status == APR_EGENERAL) {
713+ /* resource shortage or should-not-occur occured */
714+ clean_child_exit(1);
715+ }
716+ else if (status != APR_SUCCESS) {
717+ continue;
718+ }
719+
720+ /*
721+ * We now have a connection, so set it up with the appropriate
722+ * socket options, file descriptors, and read/write buffers.
723+ */
724+
725+ {
726+ pid_t pid = fork(), child_pid;
727+ int status;
728+ switch (pid) {
729+ case -1:
730+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "fork: Unable to fork new process");
731+ break;
732+ case 0: /* child */
733+ apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild);
734+ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
735+ if (current_conn) {
736+ ap_process_connection(current_conn, csd);
737+ ap_lingering_close(current_conn);
738+ }
739+ exit(0);
740+ default: /* parent; just wait for child to be done */
741+ do {
742+ child_pid = waitpid(pid, &status, 0);
743+ } while (child_pid == -1 && errno == EINTR);
744+
745+ if (child_pid != pid || !WIFEXITED(status)) {
746+ if (WIFSIGNALED(status)) {
747+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "child died with signal %u", WTERMSIG(status));
748+ } else if (WEXITSTATUS(status) != 0) {
749+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "child exited with non-zero exit status %u", WEXITSTATUS(status));
750+ } else {
751+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "waitpid() failed");
752+ }
753+ clean_child_exit(1);
754+ }
755+ break;
756+ }
757+ }
758+
759+ /* Check the pod and the generation number after processing a
760+ * connection so that we'll go away if a graceful restart occurred
761+ * while we were processing the connection or we are the lucky
762+ * idle server process that gets to die.
763+ */
764+ if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
765+ die_now = 1;
766+ }
767+ else if (ap_my_generation !=
768+ ap_scoreboard_image->global->running_generation) { /* restart? */
769+ /* yeah, this could be non-graceful restart, in which case the
770+ * parent will kill us soon enough, but why bother checking?
771+ */
772+ die_now = 1;
773+ }
774+
775+ /* if we have already setuid(), die (we can't be used anyhow) */
776+ if (getuid())
777+ die_now = 1;
778+ }
779+ clean_child_exit(0);
780+}
781+
782+
783+static int make_child(server_rec *s, int slot)
784+{
785+ int pid;
786+
787+ if (slot + 1 > ap_max_daemons_limit) {
788+ ap_max_daemons_limit = slot + 1;
789+ }
790+
791+ if (one_process) {
792+ apr_signal(SIGHUP, sig_term);
793+ /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */
794+ apr_signal(SIGINT, sig_term);
795+#ifdef SIGQUIT
796+ apr_signal(SIGQUIT, SIG_DFL);
797+#endif
798+ apr_signal(SIGTERM, sig_term);
799+ child_main(slot);
800+ return 0;
801+ }
802+
803+ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
804+ (request_rec *) NULL);
805+
806+
807+#ifdef _OSD_POSIX
808+ /* BS2000 requires a "special" version of fork() before a setuid() call */
809+ if ((pid = os_fork(unixd_config.user_name)) == -1) {
810+#elif defined(TPF)
811+ if ((pid = os_fork(s, slot)) == -1) {
812+#else
813+ if ((pid = fork()) == -1) {
814+#endif
815+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process");
816+
817+ /* fork didn't succeed. Fix the scoreboard or else
818+ * it will say SERVER_STARTING forever and ever
819+ */
820+ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD,
821+ (request_rec *) NULL);
822+
823+ /* In case system resources are maxxed out, we don't want
824+ * Apache running away with the CPU trying to fork over and
825+ * over and over again.
826+ */
827+ sleep(10);
828+
829+ return -1;
830+ }
831+
832+ if (!pid) {
833+#ifdef HAVE_BINDPROCESSOR
834+ /* by default AIX binds to a single processor
835+ * this bit unbinds children which will then bind to another cpu
836+ */
837+ int status = bindprocessor(BINDPROCESS, (int)getpid(),
838+ PROCESSOR_CLASS_ANY);
839+ if (status != OK) {
840+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
841+ ap_server_conf, "processor unbind failed %d", status);
842+ }
843+#endif
844+ RAISE_SIGSTOP(MAKE_CHILD);
845+ AP_MONCONTROL(1);
846+ /* Disable the parent's signal handlers and set up proper handling in
847+ * the child.
848+ */
849+ apr_signal(SIGHUP, just_die);
850+ apr_signal(SIGTERM, just_die);
851+ /* The child process just closes listeners on AP_SIG_GRACEFUL.
852+ * The pod is used for signalling the graceful restart.
853+ */
854+ apr_signal(AP_SIG_GRACEFUL, stop_listening);
855+ child_main(slot);
856+ }
857+
858+ ap_scoreboard_image->parent[slot].pid = pid;
859+
860+ return 0;
861+}
862+
863+
864+/* start up a bunch of children */
865+static void startup_children(int number_to_start)
866+{
867+ int i;
868+
869+ for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
870+ if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
871+ continue;
872+ }
873+ if (make_child(ap_server_conf, i) < 0) {
874+ break;
875+ }
876+ --number_to_start;
877+ }
878+}
879+
880+
881+/*
882+ * idle_spawn_rate is the number of children that will be spawned on the
883+ * next maintenance cycle if there aren't enough idle servers. It is
884+ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
885+ * without the need to spawn.
886+ */
887+static int idle_spawn_rate = 1;
888+#ifndef MAX_SPAWN_RATE
889+#define MAX_SPAWN_RATE (32)
890+#endif
891+static int hold_off_on_exponential_spawning;
892+
893+static void perform_idle_server_maintenance(apr_pool_t *p)
894+{
895+ int i;
896+ int to_kill;
897+ int idle_count;
898+ worker_score *ws;
899+ int free_length;
900+ int free_slots[MAX_SPAWN_RATE];
901+ int last_non_dead;
902+ int total_non_dead;
903+
904+ /* initialize the free_list */
905+ free_length = 0;
906+
907+ to_kill = -1;
908+ idle_count = 0;
909+ last_non_dead = -1;
910+ total_non_dead = 0;
911+
912+ for (i = 0; i < ap_daemons_limit; ++i) {
913+ int status;
914+
915+ if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
916+ break;
917+ ws = &ap_scoreboard_image->servers[i][0];
918+ status = ws->status;
919+ if (status == SERVER_DEAD) {
920+ /* try to keep children numbers as low as possible */
921+ if (free_length < idle_spawn_rate) {
922+ free_slots[free_length] = i;
923+ ++free_length;
924+ }
925+ }
926+ else {
927+ /* We consider a starting server as idle because we started it
928+ * at least a cycle ago, and if it still hasn't finished starting
929+ * then we're just going to swamp things worse by forking more.
930+ * So we hopefully won't need to fork more if we count it.
931+ * This depends on the ordering of SERVER_READY and SERVER_STARTING.
932+ */
933+ if (status <= SERVER_READY) {
934+ ++ idle_count;
935+ /* always kill the highest numbered child if we have to...
936+ * no really well thought out reason ... other than observing
937+ * the server behaviour under linux where lower numbered children
938+ * tend to service more hits (and hence are more likely to have
939+ * their data in cpu caches).
940+ */
941+ to_kill = i;
942+ }
943+
944+ ++total_non_dead;
945+ last_non_dead = i;
946+ }
947+ }
948+ ap_max_daemons_limit = last_non_dead + 1;
949+ if (idle_count > ap_daemons_max_free) {
950+ /* kill off one child... we use the pod because that'll cause it to
951+ * shut down gracefully, in case it happened to pick up a request
952+ * while we were counting
953+ */
954+ ap_mpm_pod_signal(pod);
955+ idle_spawn_rate = 1;
956+ }
957+ else if (idle_count < ap_daemons_min_free) {
958+ /* terminate the free list */
959+ if (free_length == 0) {
960+ /* only report this condition once */
961+ static int reported = 0;
962+
963+ if (!reported) {
964+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
965+ "server reached MaxClients setting, consider"
966+ " raising the MaxClients setting");
967+ reported = 1;
968+ }
969+ idle_spawn_rate = 1;
970+ }
971+ else {
972+ if (idle_spawn_rate >= 8) {
973+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
974+ "server seems busy, (you may need "
975+ "to increase StartServers, or Min/MaxSpareServers), "
976+ "spawning %d children, there are %d idle, and "
977+ "%d total children", idle_spawn_rate,
978+ idle_count, total_non_dead);
979+ }
980+ for (i = 0; i < free_length; ++i) {
981+#ifdef TPF
982+ if (make_child(ap_server_conf, free_slots[i]) == -1) {
983+ if(free_length == 1) {
984+ shutdown_pending = 1;
985+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, ap_server_conf,
986+ "No active child processes: shutting down");
987+ }
988+ }
989+#else
990+ make_child(ap_server_conf, free_slots[i]);
991+#endif /* TPF */
992+ }
993+ /* the next time around we want to spawn twice as many if this
994+ * wasn't good enough, but not if we've just done a graceful
995+ */
996+ if (hold_off_on_exponential_spawning) {
997+ --hold_off_on_exponential_spawning;
998+ }
999+ else if (idle_spawn_rate < MAX_SPAWN_RATE) {
1000+ idle_spawn_rate *= 2;
1001+ }
1002+ }
1003+ }
1004+ else {
1005+ idle_spawn_rate = 1;
1006+ }
1007+}
1008+
1009+/*****************************************************************
1010+ * Executive routines.
1011+ */
1012+
1013+int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
1014+{
1015+ int index;
1016+ int remaining_children_to_start;
1017+ apr_status_t rv;
1018+
1019+ ap_log_pid(pconf, ap_pid_fname);
1020+
1021+ first_server_limit = server_limit;
1022+ if (changed_limit_at_restart) {
1023+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1024+ "WARNING: Attempt to change ServerLimit "
1025+ "ignored during restart");
1026+ changed_limit_at_restart = 0;
1027+ }
1028+
1029+ /* Initialize cross-process accept lock */
1030+ ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT,
1031+ ap_server_root_relative(_pconf, ap_lock_fname),
1032+ ap_my_pid);
1033+
1034+ rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,
1035+ ap_accept_lock_mech, _pconf);
1036+ if (rv != APR_SUCCESS) {
1037+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
1038+ "Couldn't create accept lock (%s) (%d)",
1039+ ap_lock_fname, ap_accept_lock_mech);
1040+ mpm_state = AP_MPMQ_STOPPING;
1041+ return 1;
1042+ }
1043+
1044+#if APR_USE_SYSVSEM_SERIALIZE
1045+ if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
1046+ ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
1047+#else
1048+ if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
1049+#endif
1050+ rv = unixd_set_proc_mutex_perms(accept_mutex);
1051+ if (rv != APR_SUCCESS) {
1052+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
1053+ "Couldn't set permissions on cross-process lock; "
1054+ "check User and Group directives");
1055+ mpm_state = AP_MPMQ_STOPPING;
1056+ return 1;
1057+ }
1058+ }
1059+
1060+ if (!is_graceful) {
1061+ if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
1062+ mpm_state = AP_MPMQ_STOPPING;
1063+ return 1;
1064+ }
1065+ /* fix the generation number in the global score; we just got a new,
1066+ * cleared scoreboard
1067+ */
1068+ ap_scoreboard_image->global->running_generation = ap_my_generation;
1069+ }
1070+
1071+ set_signals();
1072+
1073+ if (one_process) {
1074+ AP_MONCONTROL(1);
1075+ make_child(ap_server_conf, 0);
1076+ }
1077+ else {
1078+ if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */
1079+ ap_daemons_max_free = ap_daemons_min_free + 1;
1080+
1081+ /* If we're doing a graceful_restart then we're going to see a lot
1082+ * of children exiting immediately when we get into the main loop
1083+ * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty
1084+ * rapidly... and for each one that exits we'll start a new one until
1085+ * we reach at least daemons_min_free. But we may be permitted to
1086+ * start more than that, so we'll just keep track of how many we're
1087+ * supposed to start up without the 1 second penalty between each fork.
1088+ */
1089+ remaining_children_to_start = ap_daemons_to_start;
1090+ if (remaining_children_to_start > ap_daemons_limit) {
1091+ remaining_children_to_start = ap_daemons_limit;
1092+ }
1093+ if (!is_graceful) {
1094+ startup_children(remaining_children_to_start);
1095+ remaining_children_to_start = 0;
1096+ }
1097+ else {
1098+ /* give the system some time to recover before kicking into
1099+ * exponential mode
1100+ */
1101+ hold_off_on_exponential_spawning = 10;
1102+ }
1103+
1104+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1105+ "%s configured -- resuming normal operations",
1106+ ap_get_server_description());
1107+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
1108+ "Server built: %s", ap_get_server_built());
1109+#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
1110+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1111+ "AcceptMutex: %s (default: %s)",
1112+ apr_proc_mutex_name(accept_mutex),
1113+ apr_proc_mutex_defname());
1114+#endif
1115+ restart_pending = shutdown_pending = 0;
1116+
1117+ mpm_state = AP_MPMQ_RUNNING;
1118+
1119+ while (!restart_pending && !shutdown_pending) {
1120+ int child_slot;
1121+ apr_exit_why_e exitwhy;
1122+ int status, processed_status;
1123+ /* this is a memory leak, but I'll fix it later. */
1124+ apr_proc_t pid;
1125+
1126+ ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
1127+
1128+ /* XXX: if it takes longer than 1 second for all our children
1129+ * to start up and get into IDLE state then we may spawn an
1130+ * extra child
1131+ */
1132+ if (pid.pid != -1) {
1133+ processed_status = ap_process_child_status(&pid, exitwhy, status);
1134+ if (processed_status == APEXIT_CHILDFATAL) {
1135+ mpm_state = AP_MPMQ_STOPPING;
1136+ return 1;
1137+ }
1138+
1139+ /* non-fatal death... note that it's gone in the scoreboard. */
1140+ child_slot = find_child_by_pid(&pid);
1141+ if (child_slot >= 0) {
1142+ (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
1143+ (request_rec *) NULL);
1144+ if (processed_status == APEXIT_CHILDSICK) {
1145+ /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
1146+ * cut the fork rate to the minimum
1147+ */
1148+ idle_spawn_rate = 1;
1149+ }
1150+ else if (remaining_children_to_start
1151+ && child_slot < ap_daemons_limit) {
1152+ /* we're still doing a 1-for-1 replacement of dead
1153+ * children with new children
1154+ */
1155+ make_child(ap_server_conf, child_slot);
1156+ --remaining_children_to_start;
1157+ }
1158+#if APR_HAS_OTHER_CHILD
1159+ }
1160+ else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) {
1161+ /* handled */
1162+#endif
1163+ }
1164+ else if (is_graceful) {
1165+ /* Great, we've probably just lost a slot in the
1166+ * scoreboard. Somehow we don't know about this
1167+ * child.
1168+ */
1169+ ap_log_error(APLOG_MARK, APLOG_WARNING,
1170+ 0, ap_server_conf,
1171+ "long lost child came home! (pid %ld)", (long)pid.pid);
1172+ }
1173+ /* Don't perform idle maintenance when a child dies,
1174+ * only do it when there's a timeout. Remember only a
1175+ * finite number of children can die, and it's pretty
1176+ * pathological for a lot to die suddenly.
1177+ */
1178+ continue;
1179+ }
1180+ else if (remaining_children_to_start) {
1181+ /* we hit a 1 second timeout in which none of the previous
1182+ * generation of children needed to be reaped... so assume
1183+ * they're all done, and pick up the slack if any is left.
1184+ */
1185+ startup_children(remaining_children_to_start);
1186+ remaining_children_to_start = 0;
1187+ /* In any event we really shouldn't do the code below because
1188+ * few of the servers we just started are in the IDLE state
1189+ * yet, so we'd mistakenly create an extra server.
1190+ */
1191+ continue;
1192+ }
1193+
1194+ perform_idle_server_maintenance(pconf);
1195+#ifdef TPF
1196+ shutdown_pending = os_check_server(tpf_server_name);
1197+ ap_check_signals();
1198+ sleep(1);
1199+#endif /*TPF */
1200+ }
1201+ } /* one_process */
1202+
1203+ mpm_state = AP_MPMQ_STOPPING;
1204+
1205+ if (shutdown_pending && !is_graceful) {
1206+ /* Time to shut down:
1207+ * Kill child processes, tell them to call child_exit, etc...
1208+ */
1209+ if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
1210+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
1211+ }
1212+ ap_reclaim_child_processes(1); /* Start with SIGTERM */
1213+
1214+ /* cleanup pid file on normal shutdown */
1215+ {
1216+ const char *pidfile = NULL;
1217+ pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1218+ if ( pidfile != NULL && unlink(pidfile) == 0)
1219+ ap_log_error(APLOG_MARK, APLOG_INFO,
1220+ 0, ap_server_conf,
1221+ "removed PID file %s (pid=%ld)",
1222+ pidfile, (long)getpid());
1223+ }
1224+
1225+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1226+ "caught SIGTERM, shutting down");
1227+
1228+ return 1;
1229+ } else if (shutdown_pending) {
1230+ /* Time to perform a graceful shut down:
1231+ * Reap the inactive children, and ask the active ones
1232+ * to close their listeners, then wait until they are
1233+ * all done to exit.
1234+ */
1235+ int active_children;
1236+ apr_time_t cutoff = 0;
1237+
1238+ /* Stop listening */
1239+ ap_close_listeners();
1240+
1241+ /* kill off the idle ones */
1242+ ap_mpm_pod_killpg(pod, ap_max_daemons_limit);
1243+
1244+ /* Send SIGUSR1 to the active children */
1245+ active_children = 0;
1246+ for (index = 0; index < ap_daemons_limit; ++index) {
1247+ if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
1248+ /* Ask each child to close its listeners. */
1249+ ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL);
1250+ active_children++;
1251+ }
1252+ }
1253+
1254+ /* Allow each child which actually finished to exit */
1255+ ap_relieve_child_processes();
1256+
1257+ /* cleanup pid file */
1258+ {
1259+ const char *pidfile = NULL;
1260+ pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1261+ if ( pidfile != NULL && unlink(pidfile) == 0)
1262+ ap_log_error(APLOG_MARK, APLOG_INFO,
1263+ 0, ap_server_conf,
1264+ "removed PID file %s (pid=%ld)",
1265+ pidfile, (long)getpid());
1266+ }
1267+
1268+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1269+ "caught " AP_SIG_GRACEFUL_STOP_STRING ", shutting down gracefully");
1270+
1271+ if (ap_graceful_shutdown_timeout) {
1272+ cutoff = apr_time_now() +
1273+ apr_time_from_sec(ap_graceful_shutdown_timeout);
1274+ }
1275+
1276+ /* Don't really exit until each child has finished */
1277+ shutdown_pending = 0;
1278+ do {
1279+ /* Pause for a second */
1280+ sleep(1);
1281+
1282+ /* Relieve any children which have now exited */
1283+ ap_relieve_child_processes();
1284+
1285+ active_children = 0;
1286+ for (index = 0; index < ap_daemons_limit; ++index) {
1287+ if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
1288+ active_children = 1;
1289+ /* Having just one child is enough to stay around */
1290+ break;
1291+ }
1292+ }
1293+ } while (!shutdown_pending && active_children &&
1294+ (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
1295+
1296+ /* We might be here because we received SIGTERM, either
1297+ * way, try and make sure that all of our processes are
1298+ * really dead.
1299+ */
1300+ unixd_killpg(getpgrp(), SIGTERM);
1301+
1302+ return 1;
1303+ }
1304+
1305+ /* we've been told to restart */
1306+ apr_signal(SIGHUP, SIG_IGN);
1307+ apr_signal(AP_SIG_GRACEFUL, SIG_IGN);
1308+ if (one_process) {
1309+ /* not worth thinking about */
1310+ return 1;
1311+ }
1312+
1313+ /* advance to the next generation */
1314+ /* XXX: we really need to make sure this new generation number isn't in
1315+ * use by any of the children.
1316+ */
1317+ ++ap_my_generation;
1318+ ap_scoreboard_image->global->running_generation = ap_my_generation;
1319+
1320+ if (is_graceful) {
1321+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1322+ "Graceful restart requested, doing restart");
1323+
1324+ /* kill off the idle ones */
1325+ ap_mpm_pod_killpg(pod, ap_max_daemons_limit);
1326+
1327+ /* This is mostly for debugging... so that we know what is still
1328+ * gracefully dealing with existing request. This will break
1329+ * in a very nasty way if we ever have the scoreboard totally
1330+ * file-based (no shared memory)
1331+ */
1332+ for (index = 0; index < ap_daemons_limit; ++index) {
1333+ if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
1334+ ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL;
1335+ /* Ask each child to close its listeners.
1336+ *
1337+ * NOTE: we use the scoreboard, because if we send SIGUSR1
1338+ * to every process in the group, this may include CGI's,
1339+ * piped loggers, etc. They almost certainly won't handle
1340+ * it gracefully.
1341+ */
1342+ ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL);
1343+ }
1344+ }
1345+ }
1346+ else {
1347+ /* Kill 'em off */
1348+ if (unixd_killpg(getpgrp(), SIGHUP) < 0) {
1349+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP");
1350+ }
1351+ ap_reclaim_child_processes(0); /* Not when just starting up */
1352+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1353+ "SIGHUP received. Attempting to restart");
1354+ }
1355+
1356+ return 0;
1357+}
1358+
1359+/* This really should be a post_config hook, but the error log is already
1360+ * redirected by that point, so we need to do this in the open_logs phase.
1361+ */
1362+static int itk_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
1363+{
1364+ apr_status_t rv;
1365+
1366+ pconf = p;
1367+ ap_server_conf = s;
1368+
1369+ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
1370+ ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
1371+ NULL, "no listening sockets available, shutting down");
1372+ return DONE;
1373+ }
1374+
1375+ if ((rv = ap_mpm_pod_open(pconf, &pod))) {
1376+ ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
1377+ "Could not open pipe-of-death.");
1378+ return DONE;
1379+ }
1380+ return OK;
1381+}
1382+
1383+static int itk_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1384+{
1385+ static int restart_num = 0;
1386+ int no_detach, debug, foreground;
1387+ apr_status_t rv;
1388+
1389+ mpm_state = AP_MPMQ_STARTING;
1390+
1391+ debug = ap_exists_config_define("DEBUG");
1392+
1393+ if (debug) {
1394+ foreground = one_process = 1;
1395+ no_detach = 0;
1396+ }
1397+ else
1398+ {
1399+ no_detach = ap_exists_config_define("NO_DETACH");
1400+ one_process = ap_exists_config_define("ONE_PROCESS");
1401+ foreground = ap_exists_config_define("FOREGROUND");
1402+ }
1403+
1404+ /* sigh, want this only the second time around */
1405+ if (restart_num++ == 1) {
1406+ is_graceful = 0;
1407+
1408+ if (!one_process && !foreground) {
1409+ rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
1410+ : APR_PROC_DETACH_DAEMONIZE);
1411+ if (rv != APR_SUCCESS) {
1412+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
1413+ "apr_proc_detach failed");
1414+ return HTTP_INTERNAL_SERVER_ERROR;
1415+ }
1416+ }
1417+
1418+ parent_pid = ap_my_pid = getpid();
1419+ }
1420+
1421+ unixd_pre_config(ptemp);
1422+ ap_listen_pre_config();
1423+ ap_daemons_to_start = DEFAULT_START_DAEMON;
1424+ ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON;
1425+ ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON;
1426+ ap_daemons_limit = server_limit;
1427+ ap_pid_fname = DEFAULT_PIDLOG;
1428+ ap_lock_fname = DEFAULT_LOCKFILE;
1429+ ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
1430+ ap_extended_status = 0;
1431+#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
1432+ ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
1433+#endif
1434+
1435+ apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1436+
1437+ return OK;
1438+}
1439+
1440+static int itk_post_perdir_config(request_rec *r)
1441+{
1442+ uid_t wanted_uid;
1443+ gid_t wanted_gid;
1444+ const char *wanted_username;
1445+ int err = 0;
1446+
1447+ itk_server_conf *sconf =
1448+ (itk_server_conf *) ap_get_module_config(r->server->module_config, &mpm_itk_module);
1449+
1450+ /* Enforce MaxClientsVhost. */
1451+ if (sconf->max_clients_vhost > 0) {
1452+ int i, num_other_servers = 0;
1453+ for (i = 0; i < ap_daemons_limit; ++i) {
1454+ worker_score *ws = &ap_scoreboard_image->servers[i][0];
1455+ if (ws->status >= SERVER_BUSY_READ && strncmp(ws->vhost, r->server->server_hostname, 31) == 0)
1456+ ++num_other_servers;
1457+ }
1458+
1459+ if (num_other_servers > sconf->max_clients_vhost) {
1460+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \
1461+ "MaxClientsVhost reached for %s, refusing client.",
1462+ r->server->server_hostname);
1463+ return HTTP_SERVICE_UNAVAILABLE;
1464+ }
1465+ }
1466+
1467+ itk_per_dir_conf *dconf =
1468+ (itk_per_dir_conf *) ap_get_module_config(r->per_dir_config, &mpm_itk_module);
1469+
1470+ strncpy(ap_scoreboard_image->servers[my_child_num][0].vhost, r->server->server_hostname, 31);
1471+ ap_scoreboard_image->servers[my_child_num][0].vhost[31] = 0;
1472+
1473+ if (dconf->nice_value != UNSET_NICE_VALUE &&
1474+ setpriority(PRIO_PROCESS, 0, dconf->nice_value)) {
1475+ _DBG("setpriority(): %s", strerror(errno));
1476+ err = 1;
1477+ }
1478+
1479+ wanted_uid = dconf->uid;
1480+ wanted_gid = dconf->gid;
1481+ wanted_username = dconf->username;
1482+
1483+ if (wanted_uid == -1 || wanted_gid == -1) {
1484+ wanted_uid = unixd_config.user_id;
1485+ wanted_gid = unixd_config.group_id;
1486+ wanted_username = unixd_config.user_name;
1487+ }
1488+
1489+ if (!err && wanted_uid != -1 && wanted_gid != -1 && (getuid() != wanted_uid || getgid() != wanted_gid)) {
1490+ if (setgid(wanted_gid)) {
1491+ _DBG("setgid(%d): %s", wanted_gid, strerror(errno));
1492+ err = 1;
1493+ } else if (initgroups(wanted_username, wanted_gid)) {
1494+ _DBG("initgroups(%s, %d): %s", wanted_username, wanted_gid, strerror(errno));
1495+ err = 1;
1496+ } else if (setuid(wanted_uid)) {
1497+ _DBG("setuid(%d): %s", wanted_uid, strerror(errno));
1498+ err = 1;
1499+ }
1500+ }
1501+
1502+ /*
1503+ * Most likely a case of switching uid/gid within a persistent
1504+ * connection; the RFCs allow us to just close the connection
1505+ * at anytime, so we excercise our right. :-)
1506+ */
1507+ if (err) {
1508+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \
1509+ "Couldn't set uid/gid/priority, closing connection.");
1510+ ap_lingering_close(r->connection);
1511+ exit(0);
1512+ }
1513+ return OK;
1514+}
1515+
1516+static void itk_hooks(apr_pool_t *p)
1517+{
1518+ /* The itk open_logs phase must run before the core's, or stderr
1519+ * will be redirected to a file, and the messages won't print to the
1520+ * console.
1521+ */
1522+ static const char *const aszSucc[] = {"core.c", NULL};
1523+
1524+#ifdef AUX3
1525+ (void) set42sig();
1526+#endif
1527+
1528+ ap_hook_open_logs(itk_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
1529+ /* we need to set the MPM state before other pre-config hooks use MPM query
1530+ * to retrieve it, so register as REALLY_FIRST
1531+ */
1532+ ap_hook_pre_config(itk_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
1533+
1534+ /* set the uid as fast as possible, but not before merging per-dit config */
1535+ ap_hook_header_parser(itk_post_perdir_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
1536+}
1537+
1538+static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
1539+{
1540+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1541+ if (err != NULL) {
1542+ return err;
1543+ }
1544+
1545+ ap_daemons_to_start = atoi(arg);
1546+ return NULL;
1547+}
1548+
1549+static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char *arg)
1550+{
1551+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1552+ if (err != NULL) {
1553+ return err;
1554+ }
1555+
1556+ ap_daemons_min_free = atoi(arg);
1557+ if (ap_daemons_min_free <= 0) {
1558+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1559+ "WARNING: detected MinSpareServers set to non-positive.");
1560+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1561+ "Resetting to 1 to avoid almost certain Apache failure.");
1562+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1563+ "Please read the documentation.");
1564+ ap_daemons_min_free = 1;
1565+ }
1566+
1567+ return NULL;
1568+}
1569+
1570+static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, const char *arg)
1571+{
1572+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1573+ if (err != NULL) {
1574+ return err;
1575+ }
1576+
1577+ ap_daemons_max_free = atoi(arg);
1578+ return NULL;
1579+}
1580+
1581+static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg)
1582+{
1583+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1584+ if (err != NULL) {
1585+ return err;
1586+ }
1587+
1588+ ap_daemons_limit = atoi(arg);
1589+ if (ap_daemons_limit > server_limit) {
1590+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1591+ "WARNING: MaxClients of %d exceeds ServerLimit value "
1592+ "of %d servers,", ap_daemons_limit, server_limit);
1593+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1594+ " lowering MaxClients to %d. To increase, please "
1595+ "see the ServerLimit", server_limit);
1596+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1597+ " directive.");
1598+ ap_daemons_limit = server_limit;
1599+ }
1600+ else if (ap_daemons_limit < 1) {
1601+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1602+ "WARNING: Require MaxClients > 0, setting to 1");
1603+ ap_daemons_limit = 1;
1604+ }
1605+ return NULL;
1606+}
1607+
1608+static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
1609+{
1610+ int tmp_server_limit;
1611+
1612+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1613+ if (err != NULL) {
1614+ return err;
1615+ }
1616+
1617+ tmp_server_limit = atoi(arg);
1618+ /* you cannot change ServerLimit across a restart; ignore
1619+ * any such attempts
1620+ */
1621+ if (first_server_limit &&
1622+ tmp_server_limit != server_limit) {
1623+ /* how do we log a message? the error log is a bit bucket at this
1624+ * point; we'll just have to set a flag so that ap_mpm_run()
1625+ * logs a warning later
1626+ */
1627+ changed_limit_at_restart = 1;
1628+ return NULL;
1629+ }
1630+ server_limit = tmp_server_limit;
1631+
1632+ if (server_limit > MAX_SERVER_LIMIT) {
1633+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1634+ "WARNING: ServerLimit of %d exceeds compile time limit "
1635+ "of %d servers,", server_limit, MAX_SERVER_LIMIT);
1636+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1637+ " lowering ServerLimit to %d.", MAX_SERVER_LIMIT);
1638+ server_limit = MAX_SERVER_LIMIT;
1639+ }
1640+ else if (server_limit < 1) {
1641+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1642+ "WARNING: Require ServerLimit > 0, setting to 1");
1643+ server_limit = 1;
1644+ }
1645+ return NULL;
1646+}
1647+
1648+static const char *assign_user_id (cmd_parms *cmd, void *ptr, const char *user_name, const char *group_name)
1649+{
1650+ itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr;
1651+ dconf->username = apr_pstrdup(cmd->pool, user_name);
1652+ dconf->uid = ap_uname2id(user_name);
1653+ dconf->gid = ap_gname2id(group_name);
1654+ return NULL;
1655+}
1656+
1657+static const char *set_max_clients_vhost (cmd_parms *cmd, void *dummy, const char *arg)
1658+{
1659+ itk_server_conf *sconf =
1660+ (itk_server_conf *) ap_get_module_config(cmd->server->module_config, &mpm_itk_module);
1661+ sconf->max_clients_vhost = atoi(arg);
1662+ return NULL;
1663+}
1664+
1665+static const char *set_nice_value (cmd_parms *cmd, void *ptr, const char *arg)
1666+{
1667+ itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr;
1668+ int nice_value = atoi(arg);
1669+
1670+ if (nice_value < -20) {
1671+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1672+ "WARNING: NiceValue of %d is below -20, increasing NiceValue to -20.",
1673+ nice_value);
1674+ nice_value = -20;
1675+ }
1676+ else if (nice_value > 19) {
1677+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1678+ "WARNING: NiceValue of %d is above 19, lowering NiceValue to 19.",
1679+ nice_value);
1680+ nice_value = 19;
1681+ }
1682+ dconf->nice_value = nice_value;
1683+ return NULL;
1684+}
1685+
1686+static const command_rec itk_cmds[] = {
1687+UNIX_DAEMON_COMMANDS,
1688+LISTEN_COMMANDS,
1689+AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
1690+ "Number of child processes launched at server startup"),
1691+AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF,
1692+ "Minimum number of idle children, to handle request spikes"),
1693+AP_INIT_TAKE1("MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF,
1694+ "Maximum number of idle children"),
1695+AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
1696+ "Maximum number of children alive at the same time"),
1697+AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
1698+ "Maximum value of MaxClients for this run of Apache"),
1699+AP_INIT_TAKE2("AssignUserID", assign_user_id, NULL, RSRC_CONF|ACCESS_CONF,
1700+ "Tie a virtual host to a specific child process."),
1701+AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF,
1702+ "Maximum number of children alive at the same time for this virtual host."),
1703+AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF,
1704+ "Set nice value for the given vhost, from -20 (highest priority) to 19 (lowest priority)."),
1705+AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
1706+{ NULL }
1707+};
1708+
1709+/* == allocate a private per-dir config structure == */
1710+static void *itk_create_dir_config(apr_pool_t *p, char *dummy)
1711+{
1712+ itk_per_dir_conf *c = (itk_per_dir_conf *)
1713+ apr_pcalloc(p, sizeof(itk_per_dir_conf));
1714+ c->uid = c->gid = -1;
1715+ c->nice_value = UNSET_NICE_VALUE;
1716+ return c;
1717+}
1718+
1719+/* == merge the parent per-dir config structure into ours == */
1720+static void *itk_merge_dir_config(apr_pool_t *p, void *parent_ptr, void *child_ptr)
1721+{
1722+ itk_per_dir_conf *c = (itk_per_dir_conf *)
1723+ apr_pcalloc(p, sizeof(itk_per_dir_conf));
1724+ itk_per_dir_conf *parent = (itk_per_dir_conf *) parent_ptr;
1725+ itk_per_dir_conf *child = (itk_per_dir_conf *) child_ptr;
1726+
1727+ if (child->username != NULL) {
1728+ c->username = apr_pstrdup(p, child->username);
1729+ c->uid = child->uid;
1730+ c->gid = child->gid;
1731+ } else if (parent->username != NULL) {
1732+ c->username = apr_pstrdup(p, parent->username);
1733+ c->uid = parent->uid;
1734+ c->gid = parent->gid;
1735+ }
1736+ if (child->nice_value != UNSET_NICE_VALUE) {
1737+ c->nice_value = child->nice_value;
1738+ } else {
1739+ c->nice_value = parent->nice_value;
1740+ }
1741+ return c;
1742+}
1743+
1744+/* == allocate a private server config structure == */
1745+static void *itk_create_server_config(apr_pool_t *p, server_rec *s)
1746+{
1747+ itk_server_conf *c = (itk_server_conf *)
1748+ apr_pcalloc(p, sizeof(itk_server_conf));
1749+ c->max_clients_vhost = -1;
1750+ return c;
1751+}
1752+
1753+module AP_MODULE_DECLARE_DATA mpm_itk_module = {
1754+ MPM20_MODULE_STUFF,
1755+ ap_mpm_rewrite_args, /* hook to run before apache parses args */
1756+ itk_create_dir_config, /* create per-directory config structure */
1757+ itk_merge_dir_config, /* merge per-directory config structures */
1758+ itk_create_server_config, /* create per-server config structure */
1759+ NULL, /* merge per-server config structures */
1760+ itk_cmds, /* command apr_table_t */
1761+ itk_hooks, /* register hooks */
1762+};
1763unchanged:
1764--- httpd-2.2.11/server/mpm/experimental/itk/mpm.h 2009-03-17 21:39:03.000000000 +0100
1765+++ httpd-2.2.11/server/mpm/experimental/itk/mpm.h 2009-03-21 13:02:33.000000000 +0100
1766@@ -0,0 +1,68 @@
1767+/* Licensed to the Apache Software Foundation (ASF) under one or more
1768+ * contributor license agreements. See the NOTICE file distributed with
1769+ * this work for additional information regarding copyright ownership.
1770+ * The ASF licenses this file to You under the Apache License, Version 2.0
1771+ * (the "License"); you may not use this file except in compliance with
1772+ * the License. You may obtain a copy of the License at
1773+ *
1774+ * http://www.apache.org/licenses/LICENSE-2.0
1775+ *
1776+ * Unless required by applicable law or agreed to in writing, software
1777+ * distributed under the License is distributed on an "AS IS" BASIS,
1778+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1779+ * See the License for the specific language governing permissions and
1780+ * limitations under the License.
1781+ *
1782+ * Portions copyright 2005-2009 Steinar H. Gunderson <sgunderson@bigfoot.com>.
1783+ * Licensed under the same terms as the rest of Apache.
1784+ *
1785+ * Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>.
1786+ * Licensed under the same terms as the rest of Apache.
1787+ */
1788+
1789+/**
1790+ * @file itk/mpm.h
1791+ * @brief ITK MPM (setuid per-vhost, no threads)
1792+ *
1793+ * @defgroup APACHE_MPM_ITK Apache ITK
1794+ * @ingroup APACHE_MPM APACHE_OS_UNIX
1795+ * @{
1796+ */
1797+
1798+#include "httpd.h"
1799+#include "mpm_default.h"
1800+#include "scoreboard.h"
1801+#include "unixd.h"
1802+
1803+#ifndef APACHE_MPM_ITK_H
1804+#define APACHE_MPM_ITK_H
1805+
1806+#define ITK_MPM
1807+
1808+#define MPM_NAME "ITK"
1809+
1810+#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
1811+#define AP_MPM_WANT_WAIT_OR_TIMEOUT
1812+#define AP_MPM_WANT_PROCESS_CHILD_STATUS
1813+#define AP_MPM_WANT_SET_PIDFILE
1814+#define AP_MPM_WANT_SET_SCOREBOARD
1815+#define AP_MPM_WANT_SET_LOCKFILE
1816+#define AP_MPM_WANT_SET_MAX_REQUESTS
1817+#define AP_MPM_WANT_SET_COREDUMPDIR
1818+#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
1819+#define AP_MPM_WANT_SIGNAL_SERVER
1820+#define AP_MPM_WANT_SET_MAX_MEM_FREE
1821+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
1822+#define AP_MPM_WANT_SET_GRACEFUL_SHUTDOWN
1823+#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
1824+
1825+#define AP_MPM_USES_POD 1
1826+#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
1827+#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
1828+#define MPM_ACCEPT_FUNC unixd_accept
1829+
1830+extern int ap_threads_per_child;
1831+extern int ap_max_daemons_limit;
1832+extern server_rec *ap_server_conf;
1833+#endif /* APACHE_MPM_ITK_H */
1834+/** @} */
1835unchanged:
1836--- httpd-2.2.11/server/mpm/experimental/itk/mpm_default.h 2009-03-17 21:39:03.000000000 +0100
1837+++ httpd-2.2.11/server/mpm/experimental/itk/mpm_default.h 2009-03-21 13:02:33.000000000 +0100
1838@@ -0,0 +1,80 @@
1839+/* Licensed to the Apache Software Foundation (ASF) under one or more
1840+ * contributor license agreements. See the NOTICE file distributed with
1841+ * this work for additional information regarding copyright ownership.
1842+ * The ASF licenses this file to You under the Apache License, Version 2.0
1843+ * (the "License"); you may not use this file except in compliance with
1844+ * the License. You may obtain a copy of the License at
1845+ *
1846+ * http://www.apache.org/licenses/LICENSE-2.0
1847+ *
1848+ * Unless required by applicable law or agreed to in writing, software
1849+ * distributed under the License is distributed on an "AS IS" BASIS,
1850+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1851+ * See the License for the specific language governing permissions and
1852+ * limitations under the License.
1853+ *
1854+ * Portions copyright 2005-2009 Steinar H. Gunderson <sgunderson@bigfoot.com>.
1855+ * Licensed under the same terms as the rest of Apache.
1856+ *
1857+ * Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>.
1858+ * Licensed under the same terms as the rest of Apache.
1859+ */
1860+
1861+/**
1862+ * @file itk/mpm_default.h
1863+ * @brief ITK MPM defaults
1864+ *
1865+ * @addtogroup APACHE_MPM_ITK
1866+ * @{
1867+ */
1868+
1869+#ifndef APACHE_MPM_DEFAULT_H
1870+#define APACHE_MPM_DEFAULT_H
1871+
1872+/* Number of servers to spawn off by default --- also, if fewer than
1873+ * this free when the caretaker checks, it will spawn more.
1874+ */
1875+#ifndef DEFAULT_START_DAEMON
1876+#define DEFAULT_START_DAEMON 5
1877+#endif
1878+
1879+/* Maximum number of *free* server processes --- more than this, and
1880+ * they will die off.
1881+ */
1882+
1883+#ifndef DEFAULT_MAX_FREE_DAEMON
1884+#define DEFAULT_MAX_FREE_DAEMON 10
1885+#endif
1886+
1887+/* Minimum --- fewer than this, and more will be created */
1888+
1889+#ifndef DEFAULT_MIN_FREE_DAEMON
1890+#define DEFAULT_MIN_FREE_DAEMON 5
1891+#endif
1892+
1893+/* File used for accept locking, when we use a file */
1894+#ifndef DEFAULT_LOCKFILE
1895+#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock"
1896+#endif
1897+
1898+/* Where the main/parent process's pid is logged */
1899+#ifndef DEFAULT_PIDLOG
1900+#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid"
1901+#endif
1902+
1903+/*
1904+ * Interval, in microseconds, between scoreboard maintenance.
1905+ */
1906+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
1907+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
1908+#endif
1909+
1910+/* Number of requests to try to handle in a single process. If <= 0,
1911+ * the children don't die off.
1912+ */
1913+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
1914+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
1915+#endif
1916+
1917+#endif /* AP_MPM_DEFAULT_H */
1918+/** @} */
1919unchanged:
1920--- apache2.2.orig/server/mpm/config.m4 2007-01-29 21:30:26.000000000 +0100
1921+++ apache2.2/server/mpm/config.m4 2007-01-29 21:30:35.000000000 +0100
1922@@ -1,7 +1,7 @@
1923 AC_MSG_CHECKING(which MPM to use)
1924 AC_ARG_WITH(mpm,
1925 APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use.
8aee8e51
AM
1926- MPM={beos|event|worker|prefork|mpmt_os2|winnt}),[
1927+ MPM={beos|event|worker|prefork|mpmt_os2|winnt|itk}),[
7dda4a20
JR
1928 APACHE_MPM=$withval
1929 ],[
1930 if test "x$APACHE_MPM" = "x"; then
1931@@ -23,7 +23,7 @@
1932
1933 ap_mpm_is_experimental ()
1934 {
1935- if test "$apache_cv_mpm" = "event" ; then
1936+ if test "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "itk" ; then
1937 return 0
1938 else
1939 return 1
1940unchanged:
1941--- apache2.2.orig/server/mpm/experimental/itk/config.m4 2007-01-29 21:03:51.000000000 +0100
1942+++ apache2.2/server/mpm/experimental/itk/config.m4 2007-01-29 21:03:57.000000000 +0100
1943@@ -1,3 +1,3 @@
1944 if test "$MPM_NAME" = "itk" ; then
1945- APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
1946+ APACHE_FAST_OUTPUT(server/mpm/$MPM_SUBDIR_NAME/Makefile)
1947 fi
1948unchanged:
1949--- httpd-2.2.11/include/http_request.h 2009-03-21 13:03:31.000000000 +0100
1950+++ httpd-2.2.11/include/http_request.h 2009-03-21 13:03:41.000000000 +0100
1951@@ -12,6 +12,12 @@
1952 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1953 * See the License for the specific language governing permissions and
1954 * limitations under the License.
1955+ *
1956+ * Portions copyright 2005-2009 Steinar H. Gunderson <sgunderson@bigfoot.com>.
1957+ * Licensed under the same terms as the rest of Apache.
1958+ *
1959+ * Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>.
1960+ * Licensed under the same terms as the rest of Apache.
1961 */
1962
1963 /**
1964@@ -350,6 +356,15 @@
1965 */
1966 AP_DECLARE_HOOK(void,insert_filter,(request_rec *r))
1967
1968+/**
1969+ * This hook allows modules to affect the request immediately after the
1970+ * per-directory configuration for the request has been generated. This allows
1971+ * modules to make decisions based upon the current directory configuration
1972+ * @param r The current request
1973+ * @return OK or DECLINED
1974+ */
1975+AP_DECLARE_HOOK(int,post_perdir_config,(request_rec *r))
1976+
1977 AP_DECLARE(int) ap_location_walk(request_rec *r);
1978 AP_DECLARE(int) ap_directory_walk(request_rec *r);
1979 AP_DECLARE(int) ap_file_walk(request_rec *r);
1980unchanged:
1981--- httpd-2.2.11/server/request.c 2009-03-21 13:03:13.000000000 +0100
1982+++ httpd-2.2.11/server/request.c 2009-03-21 13:03:41.000000000 +0100
1983@@ -12,6 +12,12 @@
1984 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1985 * See the License for the specific language governing permissions and
1986 * limitations under the License.
1987+ *
1988+ * Portions copyright 2005-2009 Steinar H. Gunderson <sgunderson@bigfoot.com>.
1989+ * Licensed under the same terms as the rest of Apache.
1990+ *
1991+ * Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>.
1992+ * Licensed under the same terms as the rest of Apache.
1993 */
1994
1995 /*
1996@@ -61,6 +67,7 @@
1997 APR_HOOK_LINK(auth_checker)
1998 APR_HOOK_LINK(insert_filter)
1999 APR_HOOK_LINK(create_request)
2000+ APR_HOOK_LINK(post_perdir_config)
2001 )
2002
2003 AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
2004@@ -80,6 +87,8 @@
2005 AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
2006 AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request,
2007 (request_rec *r), (r), OK, DECLINED)
2008+AP_IMPLEMENT_HOOK_RUN_ALL(int,post_perdir_config,
2009+ (request_rec *r), (r), OK, DECLINED)
2010
2011
2012 static int decl_die(int status, char *phase, request_rec *r)
2013@@ -158,6 +167,13 @@
2014 return access_status;
2015 }
2016
2017+ /* First chance to handle the request after per-directory configuration is
2018+ * generated
2019+ */
2020+ if ((access_status = ap_run_post_perdir_config(r))) {
2021+ return access_status;
2022+ }
2023+
2024 /* Only on the main request! */
2025 if (r->main == NULL) {
2026 if ((access_status = ap_run_header_parser(r))) {
2027unchanged:
2028--- httpd-2.2.11.orig/server/mpm/config.m4 2009-04-14 23:26:41.000000000 +0200
2029+++ httpd-2.2.11/server/mpm/config.m4 2009-04-14 23:28:03.000000000 +0200
2030@@ -66,6 +66,11 @@
2031 else
2032 MPM_SUBDIR_NAME=$MPM_NAME
2033 fi
2034+
2035+if test "$apache_cv_mpm" = "itk" ; then
2036+ AC_CHECK_LIB(cap, cap_init)
2037+fi
2038+
2039 MPM_DIR=server/mpm/$MPM_SUBDIR_NAME
2040 MPM_LIB=$MPM_DIR/lib${MPM_NAME}.la
2041
This page took 0.580423 seconds and 4 git commands to generate.