View | Details | Raw Unified | Return to bug 137953
Collapse All | Expand All

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

Return to bug 137953