upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / server / mpm / experimental / perchild / perchild.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_hash.h"
18 #include "apr_strings.h"
19 #include "apr_pools.h"
20 #include "apr_portable.h"
21 #include "apr_file_io.h"
22 #include "apr_signal.h"
23
24 #define APR_WANT_IOVEC
25 #include "apr_want.h"
26
27 #if APR_HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #if APR_HAVE_SYS_SOCKET_H
31 #include <sys/socket.h>
32 #endif
33
34 #if !APR_HAS_THREADS
35 #error The perchild MPM requires APR threads, but they are unavailable.
36 #endif  
37
38 #define CORE_PRIVATE 
39  
40 #include "ap_config.h"
41 #include "httpd.h" 
42 #include "http_main.h" 
43 #include "http_log.h" 
44 #include "http_config.h"    /* for read_config */ 
45 #include "http_core.h"      /* for get_remote_host */ 
46 #include "http_protocol.h"
47 #include "http_connection.h"
48 #include "ap_mpm.h"
49 #include "unixd.h"
50 #include "mpm_common.h"
51 #include "ap_listen.h"
52 #include "mpm_default.h"
53 #include "mpm.h"
54 #include "scoreboard.h"
55 #include "util_filter.h"
56 #include "apr_poll.h"
57
58 #ifdef HAVE_POLL_H
59 #include <poll.h>
60 #endif
61 #ifdef HAVE_SYS_POLL_H
62 #include <sys/poll.h>
63 #endif
64
65 /* ### should be APR-ized */
66 #include <grp.h>
67 #include <pwd.h>
68 #include <sys/stat.h>
69 #include <sys/un.h>
70 #include <setjmp.h>
71 #ifdef HAVE_SYS_PROCESSOR_H
72 #include <sys/processor.h> /* for bindprocessor() */
73 #endif
74
75 /*
76  * Define some magic numbers that we use for the state of the incomming
77  * request. These must be < 0 so they don't collide with a file descriptor.
78  */
79 #define AP_PERCHILD_THISCHILD -1
80 #define AP_PERCHILD_OTHERCHILD -2
81
82 /* Limit on the threads per process.  Clients will be locked out if more than
83  * this * server_limit are needed.
84  *
85  * We keep this for one reason it keeps the size of the scoreboard file small
86  * enough that we can read the whole thing without worrying too much about
87  * the overhead.
88  */
89 #ifndef DEFAULT_THREAD_LIMIT
90 #define DEFAULT_THREAD_LIMIT 64 
91 #endif
92
93 /* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT.  We want
94  * some sort of compile-time limit to help catch typos.
95  */
96 #ifndef MAX_THREAD_LIMIT
97 #define MAX_THREAD_LIMIT 20000
98 #endif 
99
100 /* Limit on the total --- clients will be locked out if more servers than
101  * this are needed.  It is intended solely to keep the server from crashing
102  * when things get out of hand.
103  *
104  * We keep a hard maximum number of servers, for two reasons --- first off,
105  * in case something goes seriously wrong, we want to stop the fork bomb
106  * short of actually crashing the machine we're running on by filling some
107  * kernel table.  Secondly, it keeps the size of the scoreboard file small
108  * enough that we can read the whole thing without worrying too much about
109  * the overhead.
110  */
111 #ifndef DEFAULT_SERVER_LIMIT
112 #define DEFAULT_SERVER_LIMIT 8 
113 #endif
114
115 /* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT.  We want
116  * some sort of compile-time limit to help catch typos.
117  */
118 #ifndef MAX_SERVER_LIMIT
119 #define MAX_SERVER_LIMIT 20000
120 #endif
121
122 /*
123  * Actual definitions of config globals
124  */
125
126 static int threads_to_start = 0;         /* Worker threads per child */
127 static int min_spare_threads = 0;
128 static int max_spare_threads = 0;
129 static int max_threads = 0;
130 static int server_limit = DEFAULT_SERVER_LIMIT;
131 static int first_server_limit;
132 static int thread_limit = DEFAULT_THREAD_LIMIT;
133 static int first_thread_limit;
134 static int changed_limit_at_restart;
135 static int num_daemons = 0;
136 static int curr_child_num = 0;
137 static int workers_may_exit = 0;
138 static int requests_this_child;
139 static int num_listensocks = 0;
140 static ap_pod_t *pod;
141 static jmp_buf jmpbuffer;
142
143 struct child_info_t {
144     uid_t uid;
145     gid_t gid;
146     int input;       /* The socket descriptor */
147     int output;      /* The socket descriptor */
148 };
149
150 typedef struct {
151     const char *sockname;       /* The base name for the socket */
152     const char *fullsockname;   /* socket base name + extension */
153     int        input;           /* The socket descriptor */
154     int        output;          /* The socket descriptor */
155 } perchild_server_conf;
156
157 typedef struct child_info_t child_info_t;
158
159 /* Tables used to determine the user and group each child process should
160  * run as.  The hash table is used to correlate a server name with a child
161  * process.
162  */
163 static child_info_t *child_info_table;
164 static int          *thread_socket_table;
165 struct ap_ctable    *ap_child_table;
166
167 /*
168  * The max child slot ever assigned, preserved across restarts.  Necessary
169  * to deal with NumServers changes across AP_SIG_GRACEFUL restarts.  We 
170  * use this value to optimize routines that have to scan the entire child 
171  * table.
172  *
173  * XXX - It might not be worth keeping this code in. There aren't very
174  * many child processes in this MPM.
175  */
176 int ap_max_daemons_limit = -1;
177 int ap_threads_per_child; /* XXX not part of API!  axe it! */
178
179 module AP_MODULE_DECLARE_DATA mpm_perchild_module;
180
181 static apr_file_t *pipe_of_death_in = NULL;
182 static apr_file_t *pipe_of_death_out = NULL;
183 static apr_thread_mutex_t *pipe_of_death_mutex;
184
185 /* *Non*-shared http_main globals... */
186
187 server_rec *ap_server_conf;
188
189 /* one_process --- debugging mode variable; can be set from the command line
190  * with the -X flag.  If set, this gets you the child_main loop running
191  * in the process which originally started up (no detach, no make_child),
192  * which is a pretty nice debugging environment.  (You'll get a SIGHUP
193  * early in standalone_main; just continue through.  This is the server
194  * trying to kill off any child processes which it might have lying
195  * around --- Apache doesn't keep track of their pids, it just sends
196  * SIGHUP to the process group, ignoring it in the root process.
197  * Continue through and you'll be fine.).
198  */
199
200 static int one_process = 0;
201
202 #ifdef DEBUG_SIGSTOP
203 int raise_sigstop_flags;
204 #endif
205
206 static apr_pool_t *pconf;              /* Pool for config stuff */
207 static apr_pool_t *pchild;             /* Pool for httpd child stuff */
208 static apr_pool_t *thread_pool_parent; /* Parent of per-thread pools */
209 static apr_thread_mutex_t *thread_pool_parent_mutex;
210
211 static int child_num;
212 static unsigned int my_pid; /* Linux getpid() doesn't work except in 
213                       main thread. Use this instead */
214 /* Keep track of the number of worker threads currently active */
215 static int worker_thread_count;
216 static apr_thread_mutex_t *worker_thread_count_mutex;
217 static int *worker_thread_free_ids;
218 static apr_threadattr_t *worker_thread_attr;
219
220 /* Keep track of the number of idle worker threads */
221 static int idle_thread_count;
222 static apr_thread_mutex_t *idle_thread_count_mutex;
223
224 /* Locks for accept serialization */
225 #ifdef NO_SERIALIZED_ACCEPT
226 #define SAFE_ACCEPT(stmt) APR_SUCCESS
227 #else
228 #define SAFE_ACCEPT(stmt) (stmt)
229 static apr_proc_mutex_t *process_accept_mutex;
230 #endif /* NO_SERIALIZED_ACCEPT */
231 static apr_thread_mutex_t *thread_accept_mutex;
232
233 AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
234 {
235     switch(query_code){
236         case AP_MPMQ_MAX_DAEMON_USED:
237             *result = ap_max_daemons_limit;
238             return APR_SUCCESS;
239         case AP_MPMQ_IS_THREADED:
240             *result = AP_MPMQ_DYNAMIC;
241             return APR_SUCCESS;
242         case AP_MPMQ_IS_FORKED:
243             *result = AP_MPMQ_STATIC;
244             return APR_SUCCESS;
245         case AP_MPMQ_HARD_LIMIT_DAEMONS:
246             *result = server_limit;
247             return APR_SUCCESS;
248         case AP_MPMQ_HARD_LIMIT_THREADS:
249             *result = thread_limit;
250             return APR_SUCCESS;
251         case AP_MPMQ_MAX_THREADS:
252             *result = max_threads;
253             return APR_SUCCESS;
254         case AP_MPMQ_MIN_SPARE_DAEMONS:
255             *result = 0;
256             return APR_SUCCESS;
257         case AP_MPMQ_MIN_SPARE_THREADS:    
258             *result = min_spare_threads;
259             return APR_SUCCESS;
260         case AP_MPMQ_MAX_SPARE_DAEMONS:
261             *result = 0;
262             return APR_SUCCESS;
263         case AP_MPMQ_MAX_SPARE_THREADS:
264             *result = max_spare_threads;
265             return APR_SUCCESS;
266         case AP_MPMQ_MAX_REQUESTS_DAEMON:
267             *result = ap_max_requests_per_child;
268             return APR_SUCCESS; 
269         case AP_MPMQ_MAX_DAEMONS:
270             *result = num_daemons;
271             return APR_SUCCESS;
272     }
273     return APR_ENOTIMPL;
274 }
275
276 /* a clean exit from a child with proper cleanup */
277 static void clean_child_exit(int code)
278 {
279     if (pchild) {
280         apr_pool_destroy(pchild);
281     }
282     exit(code);
283 }
284
285 static void just_die(int sig)
286 {
287     clean_child_exit(0);
288 }
289
290 /*****************************************************************
291  * Connection structures and accounting...
292  */
293
294 /* volatile just in case */
295 static int volatile shutdown_pending;
296 static int volatile restart_pending;
297 static int volatile is_graceful;
298 static int volatile child_fatal;
299 /* we don't currently track ap_my_generation, but mod_status 
300  * references it so it must be defined */
301 ap_generation_t volatile ap_my_generation=0;
302
303 /*
304  * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
305  * functions to initiate shutdown or restart without relying on signals. 
306  * Previously this was initiated in sig_term() and restart() signal handlers, 
307  * but we want to be able to start a shutdown/restart from other sources --
308  * e.g. on Win32, from the service manager. Now the service manager can
309  * call ap_start_shutdown() or ap_start_restart() as appropiate.  Note that
310  * these functions can also be called by the child processes, since global
311  * variables are no longer used to pass on the required action to the parent.
312  *
313  * These should only be called from the parent process itself, since the
314  * parent process will use the shutdown_pending and restart_pending variables
315  * to determine whether to shutdown or restart. The child process should
316  * call signal_parent() directly to tell the parent to die -- this will
317  * cause neither of those variable to be set, which the parent will
318  * assume means something serious is wrong (which it will be, for the
319  * child to force an exit) and so do an exit anyway.
320  */
321
322 static void ap_start_shutdown(void)
323 {
324     if (shutdown_pending == 1) {
325         /* Um, is this _probably_ not an error, if the user has
326          * tried to do a shutdown twice quickly, so we won't
327          * worry about reporting it.
328          */
329         return;
330     }
331     shutdown_pending = 1;
332 }
333
334 /* do a graceful restart if graceful == 1 */
335 static void ap_start_restart(int graceful)
336 {
337
338     if (restart_pending == 1) {
339         /* Probably not an error - don't bother reporting it */
340         return;
341     }
342     restart_pending = 1;
343     is_graceful = graceful;
344 }
345
346 static void sig_term(int sig)
347 {
348     ap_start_shutdown();
349 }
350
351 static void restart(int sig)
352 {
353 #ifndef WIN32
354     ap_start_restart(sig == AP_SIG_GRACEFUL);
355 #else
356     ap_start_restart(1);
357 #endif
358 }
359
360 static void set_signals(void)
361 {
362 #ifndef NO_USE_SIGACTION
363     struct sigaction sa;
364 #endif
365
366     if (!one_process) {
367         ap_fatal_signal_setup(ap_server_conf, pconf);
368     }
369
370 #ifndef NO_USE_SIGACTION
371     sigemptyset(&sa.sa_mask);
372     sa.sa_flags = 0;
373
374     sa.sa_handler = sig_term;
375     if (sigaction(SIGTERM, &sa, NULL) < 0)
376         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
377                      "sigaction(SIGTERM)");
378 #ifdef SIGINT
379     if (sigaction(SIGINT, &sa, NULL) < 0)
380         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
381                      "sigaction(SIGINT)");
382 #endif
383 #ifdef SIGXCPU
384     sa.sa_handler = SIG_DFL;
385     if (sigaction(SIGXCPU, &sa, NULL) < 0)
386         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
387                      "sigaction(SIGXCPU)");
388 #endif
389 #ifdef SIGXFSZ
390     sa.sa_handler = SIG_DFL;
391     if (sigaction(SIGXFSZ, &sa, NULL) < 0)
392         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
393                      "sigaction(SIGXFSZ)");
394 #endif
395 #ifdef SIGPIPE
396     sa.sa_handler = SIG_IGN;
397     if (sigaction(SIGPIPE, &sa, NULL) < 0)
398         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
399                      "sigaction(SIGPIPE)");
400 #endif
401
402     /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy 
403      * processing one */
404     sigaddset(&sa.sa_mask, SIGHUP);
405     sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
406     sa.sa_handler = restart;
407     if (sigaction(SIGHUP, &sa, NULL) < 0)
408         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
409                      "sigaction(SIGHUP)");
410     if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
411         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
412                      "sigaction(" AP_SIG_GRACEFUL_STRING ")");
413 #else
414     if (!one_process) {
415 #ifdef SIGXCPU
416         apr_signal(SIGXCPU, SIG_DFL);
417 #endif /* SIGXCPU */
418 #ifdef SIGXFSZ
419         apr_signal(SIGXFSZ, SIG_DFL);
420 #endif /* SIGXFSZ */
421     }
422
423     apr_signal(SIGTERM, sig_term);
424 #ifdef SIGHUP
425     apr_signal(SIGHUP, restart);
426 #endif /* SIGHUP */
427 #ifdef AP_SIG_GRACEFUL
428     apr_signal(AP_SIG_GRACEFUL, restart);
429 #endif /* AP_SIG_GRACEFUL */
430 #ifdef SIGPIPE
431     apr_signal(SIGPIPE, SIG_IGN);
432 #endif /* SIGPIPE */
433
434 #endif
435 }
436
437 /*****************************************************************
438  * Here follows a long bunch of generic server bookkeeping stuff...
439  */
440
441 int ap_graceful_stop_signalled(void)
442 {
443     /* XXX - Does this really work? - Manoj */
444     return is_graceful;
445 }
446
447 /*****************************************************************
448  * Child process main loop.
449  */
450
451 static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id,
452                            apr_bucket_alloc_t *bucket_alloc)
453 {
454     conn_rec *current_conn;
455     int csd;
456     apr_status_t rv;
457     int thread_num = conn_id % thread_limit;
458     ap_sb_handle_t *sbh;
459
460     if ((rv = apr_os_sock_get(&csd, sock)) != APR_SUCCESS) {
461         ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get");
462     }
463
464     if (thread_socket_table[thread_num] < 0) {
465         ap_sock_disable_nagle(sock);
466     }
467
468     ap_create_sb_handle(&sbh, p, conn_id / thread_limit, thread_num);
469     current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, 
470                                             sbh, bucket_alloc);
471     if (current_conn) {
472         ap_process_connection(current_conn, sock);
473         ap_lingering_close(current_conn);
474     }
475 }
476
477 static int perchild_process_connection(conn_rec *c)
478 {
479     ap_filter_t *f;
480     apr_bucket_brigade *bb;
481     core_net_rec *net;
482
483     apr_pool_userdata_get((void **)&bb, "PERCHILD_SOCKETS", c->pool);
484     if (bb != NULL) {
485         for (f = c->output_filters; f != NULL; f = f->next) {
486             if (!strcmp(f->frec->name, "core")) {
487                 break;
488             }
489         }
490         if (f != NULL) {
491             net = f->ctx;
492             net->in_ctx = apr_palloc(c->pool, sizeof(*net->in_ctx));
493             net->in_ctx->b = bb;
494         }
495     }
496     return DECLINED;
497 }
498     
499
500 static void *worker_thread(apr_thread_t *, void *);
501
502 /* Starts a thread as long as we're below max_threads */
503 static int start_thread(void)
504 {
505     apr_thread_t *thread;
506     int rc;
507
508     apr_thread_mutex_lock(worker_thread_count_mutex);
509     if (worker_thread_count < max_threads - 1) {
510         rc = apr_thread_create(&thread, worker_thread_attr, worker_thread,
511                  &worker_thread_free_ids[worker_thread_count], pchild);
512         if (rc != APR_SUCCESS) {
513             ap_log_error(APLOG_MARK, APLOG_ALERT, rc, ap_server_conf,
514                          "apr_thread_create: unable to create worker thread");
515             /* In case system resources are maxxed out, we don't want
516                Apache running away with the CPU trying to fork over and
517                over and over again if we exit. */
518             sleep(10);
519             workers_may_exit = 1;
520             apr_thread_mutex_unlock(worker_thread_count_mutex);
521             return 0;
522         }
523         else {
524             worker_thread_count++;
525         }
526     }
527     else {
528         static int reported = 0;
529         
530         if (!reported) {
531             ap_log_error(APLOG_MARK, APLOG_ERR, 0,
532                          ap_server_conf,
533                          "server reached MaxThreadsPerChild setting, "
534                          "consider raising the MaxThreadsPerChild or "
535                          "NumServers settings");
536             reported = 1;
537         }
538         apr_thread_mutex_unlock(worker_thread_count_mutex);
539         return 0;
540     }
541     apr_thread_mutex_unlock(worker_thread_count_mutex);
542     return 1;
543
544 }
545
546 /* Sets workers_may_exit if we received a character on the pipe_of_death */
547 static apr_status_t check_pipe_of_death(void **csd, ap_listen_rec *lr,
548                                         apr_pool_t *ptrans)
549 {
550     apr_thread_mutex_lock(pipe_of_death_mutex);
551     if (!workers_may_exit) {
552         int ret;
553         char pipe_read_char;
554         apr_size_t n = 1;
555
556         ret = apr_recv(lr->sd, &pipe_read_char, &n);
557         if (APR_STATUS_IS_EAGAIN(ret)) {
558             /* It lost the lottery. It must continue to suffer
559              * through a life of servitude. */
560         }
561         else {
562             /* It won the lottery (or something else is very
563              * wrong). Embrace death with open arms. */
564             workers_may_exit = 1;
565         }
566     }
567     apr_thread_mutex_unlock(pipe_of_death_mutex);
568     return APR_SUCCESS;
569 }
570
571 static apr_status_t receive_from_other_child(void **csd, ap_listen_rec *lr,
572                                              apr_pool_t *ptrans)
573 {
574     struct msghdr msg;
575     struct cmsghdr *cmsg;
576     char buffer[HUGE_STRING_LEN * 2], *headers, *body;
577     int headerslen, bodylen;
578     struct iovec iov;
579     int ret, dp;
580     apr_os_sock_t sd;
581     apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans);
582     apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc);
583     apr_bucket *bucket;
584
585     apr_os_sock_get(&sd, lr->sd);
586
587     iov.iov_base = buffer;
588     iov.iov_len = sizeof(buffer);
589
590     msg.msg_name = NULL;
591     msg.msg_namelen = 0;
592     msg.msg_iov = &iov;
593     msg.msg_iovlen = 1;
594
595     cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(sd));
596     cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sd);
597     msg.msg_control = cmsg;
598     msg.msg_controllen = cmsg->cmsg_len;
599
600     ret = recvmsg(sd, &msg, 0);
601
602     memcpy(&dp, CMSG_DATA(cmsg), sizeof(dp));
603
604     *csd = NULL; /* tell apr_os_sock_put() to allocate new apr_socket_t */
605     apr_os_sock_put((apr_socket_t **)csd, &dp, ptrans);
606
607     bucket = apr_bucket_eos_create(alloc);
608     APR_BRIGADE_INSERT_HEAD(bb, bucket);
609     bucket = apr_bucket_socket_create(*csd, alloc);
610     APR_BRIGADE_INSERT_HEAD(bb, bucket);
611
612     body = strchr(iov.iov_base, 0);
613     if (!body) {
614         return 1;
615     }
616
617     body++;
618     bodylen = strlen(body);
619
620     headers = iov.iov_base;
621     headerslen = body - headers;
622
623     bucket = apr_bucket_heap_create(body, bodylen, NULL, alloc);
624     APR_BRIGADE_INSERT_HEAD(bb, bucket);
625     bucket = apr_bucket_heap_create(headers, headerslen, NULL, alloc);
626     APR_BRIGADE_INSERT_HEAD(bb, bucket);
627
628     apr_pool_userdata_set(bb, "PERCHILD_SOCKETS", NULL, ptrans);
629
630     return 0;
631 }
632
633 /* idle_thread_count should be incremented before starting a worker_thread */
634
635 static void *worker_thread(apr_thread_t *thd, void *arg)
636 {
637     void *csd;
638     apr_pool_t *tpool;      /* Pool for this thread           */
639     apr_pool_t *ptrans;     /* Pool for per-transaction stuff */
640     volatile int thread_just_started = 1;
641     int srv;
642     int thread_num = *((int *) arg);
643     long conn_id = child_num * thread_limit + thread_num;
644     apr_pollfd_t *pollset;
645     apr_status_t rv;
646     ap_listen_rec *lr, *last_lr = ap_listeners;
647     int n;
648     apr_bucket_alloc_t *bucket_alloc;
649
650     apr_thread_mutex_lock(thread_pool_parent_mutex);
651     apr_pool_create(&tpool, thread_pool_parent);
652     apr_thread_mutex_unlock(thread_pool_parent_mutex);
653     apr_pool_create(&ptrans, tpool);
654
655     (void) ap_update_child_status_from_indexes(child_num, thread_num, 
656                                                SERVER_STARTING,
657                                                (request_rec *) NULL);
658
659     bucket_alloc = apr_bucket_alloc_create(apr_thread_pool_get(thd));
660
661     apr_poll_setup(&pollset, num_listensocks, tpool);
662     for(lr = ap_listeners; lr != NULL; lr = lr->next) {
663         int fd;
664         apr_poll_socket_add(pollset, lr->sd, APR_POLLIN);
665
666         apr_os_sock_get(&fd, lr->sd);
667     }
668
669     while (!workers_may_exit) {
670         workers_may_exit |= ((ap_max_requests_per_child != 0)
671                             && (requests_this_child <= 0));
672         if (workers_may_exit) break;
673         if (!thread_just_started) {
674             apr_thread_mutex_lock(idle_thread_count_mutex);
675             if (idle_thread_count < max_spare_threads) {
676                 idle_thread_count++;
677                 apr_thread_mutex_unlock(idle_thread_count_mutex);
678             }
679             else {
680                 apr_thread_mutex_unlock(idle_thread_count_mutex);
681                 break;
682             }
683         }
684         else {
685             thread_just_started = 0;
686         }
687
688         (void) ap_update_child_status_from_indexes(child_num, thread_num, 
689                                                    SERVER_READY,
690                                                    (request_rec *) NULL);
691
692         apr_thread_mutex_lock(thread_accept_mutex);
693         if (workers_may_exit) {
694             apr_thread_mutex_unlock(thread_accept_mutex);
695             break;
696         }
697         if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(process_accept_mutex)))
698             != APR_SUCCESS) {
699             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
700                          "apr_proc_mutex_lock failed. Attempting to shutdown "
701                          "process gracefully.");
702             workers_may_exit = 1;
703         }
704
705         while (!workers_may_exit) {
706             apr_int16_t event;
707             srv = apr_poll(pollset, num_listensocks, &n, -1);
708
709             if (srv != APR_SUCCESS) {
710                 if (APR_STATUS_IS_EINTR(srv)) {
711                     continue;
712                 }
713
714                 /* apr_poll() will only return errors in catastrophic
715                  * circumstances. Let's try exiting gracefully, for now. */
716                 ap_log_error(APLOG_MARK, APLOG_ERR, srv, (const server_rec *)
717                              ap_server_conf, "apr_poll: (listen)");
718                 workers_may_exit = 1;
719             }
720             if (workers_may_exit) break;
721
722             /* find a listener */
723             lr = last_lr;
724             do {
725                 lr = lr->next;
726                 if (lr == NULL) {
727                     lr = ap_listeners;
728                 }
729                 /* XXX: Should we check for POLLERR? */
730                 apr_poll_revents_get(&event, lr->sd, pollset);
731                 if (event & (APR_POLLIN)) {
732                     last_lr = lr;
733                     goto got_fd;
734                 }
735             } while (lr != last_lr);
736         }
737     got_fd:
738         if (!workers_may_exit) {
739             rv = lr->accept_func(&csd, lr, ptrans);
740             if (rv == APR_EGENERAL) {
741                 /* E[NM]FILE, ENOMEM, etc */
742                 workers_may_exit = 1;
743             }
744             if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_accept_mutex)))
745                 != APR_SUCCESS) {
746                 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
747                              "apr_proc_mutex_unlock failed. Attempting to shutdown "
748                              "process gracefully.");
749                 workers_may_exit = 1;
750             }
751             apr_thread_mutex_unlock(thread_accept_mutex);
752             apr_thread_mutex_lock(idle_thread_count_mutex);
753             if (idle_thread_count > min_spare_threads) {
754                 idle_thread_count--;
755             }
756             else {
757                 if (!start_thread()) {
758                     idle_thread_count--;
759                 }
760             }
761             apr_thread_mutex_unlock(idle_thread_count_mutex);
762             if (setjmp(jmpbuffer) != 1) {
763                 process_socket(ptrans, csd, conn_id, bucket_alloc);
764             }
765             else {
766                 thread_socket_table[thread_num] = AP_PERCHILD_THISCHILD;
767             }  
768             requests_this_child--;
769         }
770         else {
771             if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_accept_mutex)))
772                 != APR_SUCCESS) {
773                 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
774                              "apr_proc_mutex_unlock failed. Attempting to shutdown "
775                              "process gracefully.");
776                 workers_may_exit = 1;
777             }
778             apr_thread_mutex_unlock(thread_accept_mutex);
779             apr_thread_mutex_lock(idle_thread_count_mutex);
780             idle_thread_count--;
781             apr_thread_mutex_unlock(idle_thread_count_mutex);
782         break;
783         }
784         apr_pool_clear(ptrans);
785     }
786
787     apr_thread_mutex_lock(thread_pool_parent_mutex);
788     ap_update_child_status_from_indexes(child_num, thread_num, SERVER_DEAD,
789                                         (request_rec *) NULL);
790     apr_pool_destroy(tpool);
791     apr_thread_mutex_unlock(thread_pool_parent_mutex);
792     apr_thread_mutex_lock(worker_thread_count_mutex);
793     worker_thread_count--;
794     worker_thread_free_ids[worker_thread_count] = thread_num;
795     if (worker_thread_count == 0) {
796         /* All the threads have exited, now finish the shutdown process
797          * by signalling the sigwait thread */
798         kill(my_pid, SIGTERM);
799     }
800     apr_thread_mutex_unlock(worker_thread_count_mutex);
801
802     apr_bucket_alloc_destroy(bucket_alloc);
803
804     return NULL;
805 }
806
807
808
809 /* Set group privileges.
810  *
811  * Note that we use the username as set in the config files, rather than
812  * the lookup of to uid --- the same uid may have multiple passwd entries,
813  * with different sets of groups for each.
814  */
815
816 static int set_group_privs(uid_t uid, gid_t gid)
817 {
818     if (!geteuid()) {
819         const char *name;
820
821         /* Get username if passed as a uid */
822
823         struct passwd *ent;
824
825         if ((ent = getpwuid(uid)) == NULL) {
826             ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
827                          "getpwuid: couldn't determine user name from uid %u, "
828                          "you probably need to modify the User directive",
829                          (unsigned)uid);
830             return -1;
831         }
832
833         name = ent->pw_name;
834
835         /*
836          * Set the GID before initgroups(), since on some platforms
837          * setgid() is known to zap the group list.
838          */
839         if (setgid(gid) == -1) {
840             ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
841                          "setgid: unable to set group id to Group %u",
842                          (unsigned)gid);
843             return -1;
844         }
845
846         /* Reset `groups' attributes. */
847
848         if (initgroups(name, gid) == -1) {
849             ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
850                          "initgroups: unable to set groups for User %s "
851                          "and Group %u", name, (unsigned)gid);
852             return -1;
853         }
854     }
855     return 0;
856 }
857
858
859 static int perchild_setup_child(int childnum)
860 {
861     child_info_t *ug = &child_info_table[childnum];
862
863     if (ug->uid == -1 && ug->gid == -1) {
864         return unixd_setup_child();
865     }
866     if (set_group_privs(ug->uid, ug->gid)) {
867         return -1;
868     }
869     /* Only try to switch if we're running as root */
870     if (!geteuid()
871         && (
872 #ifdef _OSD_POSIX
873             os_init_job_environment(server_conf, unixd_config.user_name,
874                                     one_process) != 0 ||
875 #endif
876             setuid(ug->uid) == -1)) {
877         ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
878                      "setuid: unable to change to uid: %ld",
879                      (long) ug->uid);
880         return -1;
881     }
882     return 0;
883 }
884
885 static int check_signal(int signum)
886 {
887     switch (signum) {
888     case SIGTERM:
889     case SIGINT:
890         just_die(signum);
891         return 1;
892     }
893     return 0;
894 }                                                                               
895
896 typedef struct perchild_header {
897     char *headers;
898     apr_pool_t *p;
899 } perchild_header;
900
901 /* Send a single HTTP header field to the client.  Note that this function
902  * is used in calls to table_do(), so their interfaces are co-dependent.
903  * In other words, don't change this one without checking table_do in alloc.c.
904  * It returns true unless there was a write error of some kind.
905  */
906 static int perchild_header_field(perchild_header *h,
907                              const char *fieldname, const char *fieldval)
908 {
909     apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL); 
910     return 1;
911 }
912
913
914 static void child_main(int child_num_arg)
915 {
916     int i;
917     apr_status_t rv;
918     apr_socket_t *sock = NULL;
919     ap_listen_rec *lr;
920     
921     my_pid = getpid();
922     ap_fatal_signal_child_setup(ap_server_conf);
923     child_num = child_num_arg;
924     apr_pool_create(&pchild, pconf);
925
926     for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) {
927         continue;
928     }
929
930     apr_os_sock_put(&sock, &child_info_table[child_num].input, pconf);
931     lr->next = apr_palloc(pconf, sizeof(*lr));
932     lr->next->sd = sock;
933     lr->next->active = 1;
934     lr->next->accept_func = receive_from_other_child;
935     lr->next->next = NULL;
936     lr = lr->next;
937     num_listensocks++;
938
939     /*stuff to do before we switch id's, so we have permissions.*/
940
941     rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&process_accept_mutex, 
942                                                ap_lock_fname, pchild));
943     if (rv != APR_SUCCESS) {
944         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
945                      "Couldn't initialize cross-process lock in child");
946         clean_child_exit(APEXIT_CHILDFATAL);
947     }
948
949     if (perchild_setup_child(child_num)) {
950         clean_child_exit(APEXIT_CHILDFATAL);
951     }
952
953     ap_run_child_init(pchild, ap_server_conf);
954
955     /*done with init critical section */
956
957     apr_setup_signal_thread();
958
959     requests_this_child = ap_max_requests_per_child;
960     
961
962     /* Setup worker threads */
963
964     if (threads_to_start > max_threads) {
965         threads_to_start = max_threads;
966     }
967     idle_thread_count = threads_to_start;
968     worker_thread_count = 0;
969     worker_thread_free_ids = (int *)apr_pcalloc(pchild, thread_limit * sizeof(int));
970     for (i = 0; i < max_threads; i++) {
971         worker_thread_free_ids[i] = i;
972     }
973     apr_pool_create(&thread_pool_parent, pchild);
974     apr_thread_mutex_create(&thread_pool_parent_mutex, 
975                     APR_THREAD_MUTEX_DEFAULT, pchild);
976     apr_thread_mutex_create(&idle_thread_count_mutex, 
977                     APR_THREAD_MUTEX_DEFAULT, pchild);
978     apr_thread_mutex_create(&worker_thread_count_mutex,
979                     APR_THREAD_MUTEX_DEFAULT, pchild);
980     apr_thread_mutex_create(&pipe_of_death_mutex,
981                     APR_THREAD_MUTEX_DEFAULT, pchild);
982     apr_thread_mutex_create(&thread_accept_mutex,
983                     APR_THREAD_MUTEX_DEFAULT, pchild);
984
985     apr_threadattr_create(&worker_thread_attr, pchild);
986     apr_threadattr_detach_set(worker_thread_attr, 1);                                     
987
988     /* We are creating worker threads right now */
989     for (i=0; i < threads_to_start; i++) {
990         /* start_thread shouldn't fail here */
991         if (!start_thread()) {
992             break;
993         }
994     }
995
996     apr_signal_thread(check_signal);
997 }
998
999 static int make_child(server_rec *s, int slot)
1000 {
1001     int pid;
1002
1003     if (slot + 1 > ap_max_daemons_limit) {
1004         ap_max_daemons_limit = slot + 1;
1005     }
1006
1007     if (one_process) {
1008         set_signals();
1009         ap_child_table[slot].pid = getpid();
1010         ap_child_table[slot].status = SERVER_ALIVE;
1011         child_main(slot);
1012     }
1013     (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
1014                                                (request_rec *) NULL);
1015
1016     if ((pid = fork()) == -1) {
1017         ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
1018                      "fork: Unable to fork new process");
1019         /* In case system resources are maxxed out, we don't want
1020          * Apache running away with the CPU trying to fork over and
1021          * over and over again. */
1022         sleep(10);
1023
1024         return -1;
1025     }
1026
1027     if (!pid) {
1028 #ifdef HAVE_BINDPROCESSOR
1029         /* By default, AIX binds to a single processor.  This bit unbinds
1030          * children which will then bind to another CPU.
1031          */
1032         int status = bindprocessor(BINDPROCESS, (int)getpid(),
1033                                    PROCESSOR_CLASS_ANY);
1034         if (status != OK) {
1035             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, 
1036                          ap_server_conf, "processor unbind failed %d", status);
1037         }
1038 #endif
1039
1040         RAISE_SIGSTOP(MAKE_CHILD);
1041
1042         /* XXX - For an unthreaded server, a signal handler will be necessary
1043          * apr_signal(SIGTERM, just_die);
1044          */
1045         child_main(slot);
1046         clean_child_exit(0);
1047     }
1048     /* else */
1049     ap_child_table[slot].pid = pid;
1050     ap_child_table[slot].status = SERVER_ALIVE;
1051
1052     return 0;
1053 }
1054
1055 /* start up a bunch of children */
1056 static int startup_children(int number_to_start)
1057 {
1058     int i;
1059
1060     for (i = 0; number_to_start && i < num_daemons; ++i) {
1061         if (ap_child_table[i].pid) {
1062             continue;
1063         }
1064         if (make_child(ap_server_conf, i) < 0) {
1065             break;
1066         }
1067         --number_to_start;
1068     }
1069     return number_to_start;
1070 }
1071
1072
1073 /*
1074  * spawn_rate is the number of children that will be spawned on the
1075  * next maintenance cycle if there aren't enough servers.  It is
1076  * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
1077  * without the need to spawn.
1078  */
1079 static int spawn_rate = 1;
1080 #ifndef MAX_SPAWN_RATE
1081 #define MAX_SPAWN_RATE  (32)
1082 #endif
1083 static int hold_off_on_exponential_spawning;
1084
1085 static void perform_child_maintenance(void)
1086 {
1087     int i;
1088     int free_length;
1089     int free_slots[MAX_SPAWN_RATE];
1090     int last_non_dead = -1;
1091
1092     /* initialize the free_list */
1093     free_length = 0;
1094     
1095     for (i = 0; i < num_daemons; ++i) {
1096         if (ap_child_table[i].pid == 0) {
1097             if (free_length < spawn_rate) {
1098                 free_slots[free_length] = i;
1099                 ++free_length;
1100             }
1101         }
1102         else {
1103             last_non_dead = i;
1104         }
1105
1106         if (i >= ap_max_daemons_limit && free_length >= spawn_rate) {
1107             break;
1108         }
1109     }
1110     ap_max_daemons_limit = last_non_dead + 1;
1111
1112     if (free_length > 0) {
1113         for (i = 0; i < free_length; ++i) {
1114             make_child(ap_server_conf, free_slots[i]);
1115         }
1116         /* the next time around we want to spawn twice as many if this
1117          * wasn't good enough, but not if we've just done a graceful
1118          */
1119         if (hold_off_on_exponential_spawning) {
1120             --hold_off_on_exponential_spawning;
1121         }
1122         else if (spawn_rate < MAX_SPAWN_RATE) {
1123             spawn_rate *= 2;
1124         }
1125     }
1126     else {
1127         spawn_rate = 1;
1128     }
1129 }
1130
1131 static void server_main_loop(int remaining_children_to_start)
1132 {
1133     int child_slot;
1134     apr_exit_why_e exitwhy;
1135     int status;
1136     apr_proc_t pid;
1137     int i;
1138
1139     while (!restart_pending && !shutdown_pending) {
1140         ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
1141         
1142         if (pid.pid != -1) {
1143             if (ap_process_child_status(&pid, exitwhy, status)
1144                 == APEXIT_CHILDFATAL) {
1145                 shutdown_pending = 1;
1146                 child_fatal = 1;
1147                 return;
1148             }
1149             /* non-fatal death... note that it's gone in the child table and
1150              * clean out the status table. */
1151             child_slot = -1;
1152             for (i = 0; i < ap_max_daemons_limit; ++i) {
1153                 if (ap_child_table[i].pid == pid.pid) {
1154                     child_slot = i;
1155                     break;
1156                 }
1157             }
1158             if (child_slot >= 0) {
1159                 ap_child_table[child_slot].pid = 0;
1160                 ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
1161                                                     (request_rec *) NULL);
1162
1163                 
1164                 if (remaining_children_to_start
1165                     && child_slot < num_daemons) {
1166                     /* we're still doing a 1-for-1 replacement of dead
1167                      * children with new children
1168                      */
1169                     make_child(ap_server_conf, child_slot);
1170                     --remaining_children_to_start;
1171                 }
1172 #if APR_HAS_OTHER_CHILD
1173             }
1174             else if (apr_proc_other_child_read(&pid, status) == 0) {
1175             /* handled */
1176 #endif
1177             }
1178             else if (is_graceful) {
1179                 /* Great, we've probably just lost a slot in the
1180                 * child table.  Somehow we don't know about this
1181                 * child.
1182                 */
1183                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, 
1184                              ap_server_conf,
1185                              "long lost child came home! (pid %ld)", 
1186                              (long)pid.pid);
1187             }
1188             /* Don't perform idle maintenance when a child dies,
1189              * only do it when there's a timeout.  Remember only a
1190              * finite number of children can die, and it's pretty
1191              * pathological for a lot to die suddenly.
1192              */
1193             continue;
1194         }
1195         else if (remaining_children_to_start) {
1196             /* we hit a 1 second timeout in which none of the previous
1197              * generation of children needed to be reaped... so assume
1198              * they're all done, and pick up the slack if any is left.
1199              */
1200             remaining_children_to_start = \
1201                 startup_children(remaining_children_to_start);
1202             /* In any event we really shouldn't do the code below because
1203              * few of the servers we just started are in the IDLE state
1204              * yet, so we'd mistakenly create an extra server.
1205              */
1206             continue;
1207         }
1208
1209         perform_child_maintenance();
1210     }
1211 }
1212
1213 int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
1214 {
1215     int remaining_children_to_start;
1216     int i;
1217     apr_status_t rv;
1218     apr_size_t one = 1;
1219     ap_listen_rec *lr;
1220     apr_socket_t *sock = NULL;
1221     int fd;
1222
1223     ap_log_pid(pconf, ap_pid_fname);
1224
1225     first_server_limit = server_limit;
1226     first_thread_limit = thread_limit;
1227     if (changed_limit_at_restart) {
1228         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1229                      "WARNING: Attempt to change ServerLimit or ThreadLimit "
1230                      "ignored during restart");
1231         changed_limit_at_restart = 0;
1232     }
1233
1234     ap_server_conf = s;
1235
1236     if ((ap_accept_lock_mech == APR_LOCK_SYSVSEM) || 
1237         (ap_accept_lock_mech == APR_LOCK_POSIXSEM)) {
1238         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1239                      "Server configured for an accept lock mechanism that "
1240                      "cannot be used with perchild.  Falling back to FCNTL.");
1241         ap_accept_lock_mech = APR_LOCK_FCNTL;
1242     }
1243
1244     /* Initialize cross-process accept lock */
1245     ap_lock_fname = apr_psprintf(_pconf, "%s.%u",
1246                                  ap_server_root_relative(_pconf, ap_lock_fname),
1247                                  my_pid);
1248     rv = SAFE_ACCEPT(apr_proc_mutex_create(&process_accept_mutex,
1249                                      ap_lock_fname, ap_accept_lock_mech,
1250                                      _pconf));
1251     if (rv != APR_SUCCESS) {
1252         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
1253                      "Couldn't create cross-process lock");
1254         return 1;
1255     }
1256
1257     if (!is_graceful) {
1258         if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
1259             return 1;
1260         }
1261     }
1262     /* Initialize the child table */
1263     if (!is_graceful) {
1264         for (i = 0; i < server_limit; i++) {
1265             ap_child_table[i].pid = 0;
1266         }
1267     }
1268
1269     /* We need to put the new listeners at the end of the ap_listeners
1270      * list.  If we don't, then the pool will be cleared before the
1271      * open_logs phase is called for the second time, and ap_listeners
1272      * will have only invalid data.  If that happens, then the sockets
1273      * that we opened using make_sock() will be lost, and the server
1274      * won't start.
1275      */
1276     for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) {
1277         continue;
1278     }
1279
1280     apr_os_file_get(&fd, pipe_of_death_in);
1281     apr_os_sock_put(&sock, &fd, pconf);
1282     lr->next = apr_palloc(pconf, sizeof(*lr));
1283     lr->next->sd = sock;
1284     lr->next->active = 1;
1285     lr->next->accept_func = check_pipe_of_death;
1286     lr->next->next = NULL;
1287     lr = lr->next;
1288     num_listensocks++;
1289
1290     set_signals();
1291
1292     /* If we're doing a graceful_restart then we're going to see a lot
1293      * of children exiting immediately when we get into the main loop
1294      * below (because we just sent them AP_SIG_GRACEFUL).  This happens 
1295      * pretty rapidly... and for each one that exits we'll start a new one 
1296      * until we reach at least daemons_min_free.  But we may be permitted to
1297      * start more than that, so we'll just keep track of how many we're
1298      * supposed to start up without the 1 second penalty between each fork.
1299      */
1300     remaining_children_to_start = num_daemons;
1301     if (!is_graceful) {
1302         remaining_children_to_start = \
1303             startup_children(remaining_children_to_start);
1304     }
1305     else {
1306         /* give the system some time to recover before kicking into
1307          * exponential mode */
1308         hold_off_on_exponential_spawning = 10;
1309     }
1310
1311     ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1312                  "%s configured -- resuming normal operations",
1313                  ap_get_server_version());
1314     ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
1315                  "Server built: %s", ap_get_server_built());
1316 #ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
1317     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1318                 "AcceptMutex: %s (default: %s)",
1319                 apr_proc_mutex_name(process_accept_mutex),
1320                 apr_proc_mutex_defname());
1321 #endif
1322     restart_pending = shutdown_pending = 0;
1323
1324     server_main_loop(remaining_children_to_start);
1325
1326     if (shutdown_pending) {
1327         /* Time to gracefully shut down:
1328          * Kill child processes, tell them to call child_exit, etc...
1329          */
1330         if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
1331             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
1332                          "killpg SIGTERM");
1333         }
1334         ap_reclaim_child_processes(1);      /* Start with SIGTERM */
1335
1336         if (!child_fatal) {
1337             /* cleanup pid file on normal shutdown */
1338             const char *pidfile = NULL;
1339             pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1340             if (pidfile != NULL && unlink(pidfile) == 0) {
1341                 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
1342                              ap_server_conf,
1343                              "removed PID file %s (pid=%ld)",
1344                              pidfile, (long)getpid());
1345             }
1346     
1347             ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1348                          ap_server_conf, "caught SIGTERM, shutting down");
1349         }
1350         return 1;
1351     }
1352
1353     /* we've been told to restart */
1354     apr_signal(SIGHUP, SIG_IGN);
1355
1356     if (one_process) {
1357         /* not worth thinking about */
1358         return 1;
1359     }
1360
1361     if (is_graceful) {
1362         char char_of_death = '!';
1363
1364         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1365                      ap_server_conf, AP_SIG_GRACEFUL_STRING " received.  "
1366                      "Doing graceful restart");
1367
1368         /* This is mostly for debugging... so that we know what is still
1369          * gracefully dealing with existing request.
1370          */
1371     
1372         for (i = 0; i < num_daemons; ++i) {
1373             if (ap_child_table[i].pid) {
1374                 ap_child_table[i].status = SERVER_DYING;
1375             } 
1376         }
1377         /* give the children the signal to die */
1378         for (i = 0; i < num_daemons;) {
1379             if ((rv = apr_file_write(pipe_of_death_out, &char_of_death,
1380                                      &one)) != APR_SUCCESS) {
1381                 if (APR_STATUS_IS_EINTR(rv)) continue;
1382                 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
1383                              "write pipe_of_death");
1384             }
1385             i++;
1386         }
1387     }
1388     else {
1389         /* Kill 'em all.  Since the child acts the same on the parents SIGTERM 
1390          * and a SIGHUP, we may as well use the same signal, because some user
1391          * pthreads are stealing signals from us left and right.
1392          */
1393         if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
1394             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
1395                          "killpg SIGTERM");
1396         }
1397         ap_reclaim_child_processes(1);      /* Start with SIGTERM */
1398         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1399                      ap_server_conf, "SIGHUP received.  Attempting to restart");
1400     }
1401     return 0;
1402 }
1403
1404 /* This really should be a post_config hook, but the error log is already
1405  * redirected by that point, so we need to do this in the open_logs phase.
1406  */
1407 static int perchild_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
1408 {
1409     apr_status_t rv;
1410
1411     pconf = p;
1412     ap_server_conf = s;
1413
1414     if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
1415         ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
1416                      NULL, "no listening sockets available, shutting down");
1417         return DONE;
1418     }
1419
1420     ap_log_pid(pconf, ap_pid_fname);
1421
1422     if ((rv = ap_mpm_pod_open(pconf, &pod))) {
1423         ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
1424                 "Could not open pipe-of-death.");
1425         return DONE;
1426     }
1427
1428     if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out,
1429                                    pconf)) != APR_SUCCESS) {
1430         ap_log_error(APLOG_MARK, APLOG_ERR, rv,
1431                      (const server_rec*) ap_server_conf,
1432                      "apr_file_pipe_create (pipe_of_death)");
1433         exit(1);
1434     }
1435     if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
1436         ap_log_error(APLOG_MARK, APLOG_ERR, rv,
1437                      (const server_rec*) ap_server_conf,
1438                      "apr_file_pipe_timeout_set (pipe_of_death)");
1439         exit(1);
1440     }
1441
1442     return OK;
1443 }
1444
1445 static int perchild_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1446 {
1447     static int restart_num = 0;
1448     int no_detach, debug, foreground;
1449     ap_directive_t *pdir;
1450     int i;
1451     int tmp_server_limit = DEFAULT_SERVER_LIMIT;
1452     int tmp_thread_limit = DEFAULT_THREAD_LIMIT;
1453     apr_status_t rv;
1454
1455     debug = ap_exists_config_define("DEBUG");
1456
1457     if (debug) {
1458         foreground = one_process = 1;
1459         no_detach = 0;
1460     }
1461     else {
1462         one_process = ap_exists_config_define("ONE_PROCESS");
1463         no_detach = ap_exists_config_define("NO_DETACH");
1464         foreground = ap_exists_config_define("FOREGROUND");
1465     }
1466
1467     /* sigh, want this only the second time around */
1468     if (restart_num++ == 1) {
1469         is_graceful = 0;
1470
1471         if (!one_process && !foreground) {
1472             rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
1473                                            : APR_PROC_DETACH_DAEMONIZE);
1474             if (rv != APR_SUCCESS) {
1475                 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
1476                              "apr_proc_detach failed");
1477                 return HTTP_INTERNAL_SERVER_ERROR;
1478             }                  
1479         }
1480
1481         my_pid = getpid();
1482     }
1483
1484     unixd_pre_config(ptemp);
1485     ap_listen_pre_config();
1486     num_daemons = DEFAULT_NUM_DAEMON;
1487     threads_to_start = DEFAULT_START_THREAD;
1488     min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
1489     max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
1490     max_threads = thread_limit;
1491     ap_pid_fname = DEFAULT_PIDLOG;
1492     ap_lock_fname = DEFAULT_LOCKFILE;
1493     ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
1494     curr_child_num = 0;
1495 #ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
1496         ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
1497 #endif
1498
1499     apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1500
1501     /* we need to know ServerLimit and ThreadLimit before we start processing
1502      * the tree because we need to already have allocated child_info_table
1503      */
1504     for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) {
1505         if (!strcasecmp(pdir->directive, "ServerLimit")) {
1506             if (atoi(pdir->args) > tmp_server_limit) {
1507                 tmp_server_limit = atoi(pdir->args);
1508                 if (tmp_server_limit > MAX_SERVER_LIMIT) {
1509                     tmp_server_limit = MAX_SERVER_LIMIT;
1510                 }
1511             }
1512         }
1513         else if (!strcasecmp(pdir->directive, "ThreadLimit")) {
1514             if (atoi(pdir->args) > tmp_thread_limit) {
1515                 tmp_thread_limit = atoi(pdir->args);
1516                 if (tmp_thread_limit > MAX_THREAD_LIMIT) {
1517                     tmp_thread_limit = MAX_THREAD_LIMIT;
1518                 }
1519             }
1520         }
1521     }
1522
1523     child_info_table = (child_info_t *)apr_pcalloc(p, tmp_server_limit * sizeof(child_info_t));
1524     for (i = 0; i < tmp_server_limit; i++) {
1525         child_info_table[i].uid = -1;
1526         child_info_table[i].gid = -1;
1527         child_info_table[i].input = -1;
1528         child_info_table[i].output = -1;
1529     }
1530
1531     return OK;
1532 }
1533
1534 static int pass_request(request_rec *r)
1535 {
1536     int rv;
1537     apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
1538     struct msghdr msg;
1539     struct cmsghdr *cmsg;
1540     int sfd;
1541     struct iovec iov[2];
1542     conn_rec *c = r->connection;
1543     apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
1544     apr_bucket_brigade *sockbb;
1545     char request_body[HUGE_STRING_LEN] = "\0";
1546     apr_size_t l = sizeof(request_body);
1547     perchild_header h;
1548     apr_bucket *sockbuck;
1549     perchild_server_conf *sconf = (perchild_server_conf *)
1550                             ap_get_module_config(r->server->module_config, 
1551                                                  &mpm_perchild_module);
1552
1553     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1554                  "passing request to another child.  Vhost: %s, child %d %d",
1555                  apr_table_get(r->headers_in, "Host"), child_num, sconf->output);
1556     ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ,
1557                    0);
1558
1559     for (sockbuck = APR_BRIGADE_FIRST(bb); sockbuck != APR_BRIGADE_SENTINEL(bb);
1560          sockbuck = APR_BUCKET_NEXT(sockbuck)) {
1561         if (APR_BUCKET_IS_SOCKET(sockbuck)) {
1562             break;
1563         }
1564     }
1565     
1566     if (!sockbuck) {
1567     }
1568     sockbb = apr_brigade_split(bb, sockbuck); 
1569
1570     if (apr_brigade_flatten(bb, request_body, &l) != APR_SUCCESS) {
1571         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1572                      "Unable to flatten brigade, declining request");
1573         return DECLINED;
1574     }
1575
1576     apr_os_sock_get(&sfd, thesock);
1577
1578     h.p = r->pool;
1579     h.headers = apr_pstrcat(h.p, r->the_request, CRLF, "Host: ", r->hostname, 
1580                             CRLF, NULL);
1581     apr_table_do((int (*) (void *, const char *, const char *))
1582                  perchild_header_field, (void *) &h, r->headers_in, NULL); 
1583     h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL);
1584
1585     iov[0].iov_base = h.headers;
1586     iov[0].iov_len = strlen(h.headers) + 1;
1587     iov[1].iov_base = request_body;
1588     iov[1].iov_len = l + 1;
1589
1590     msg.msg_name = NULL;
1591     msg.msg_namelen = 0;
1592     msg.msg_iov = iov;
1593     msg.msg_iovlen = 2;
1594
1595     cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sfd));
1596     cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sfd);
1597     cmsg->cmsg_level = SOL_SOCKET;
1598     cmsg->cmsg_type = SCM_RIGHTS;
1599
1600     memcpy(CMSG_DATA(cmsg), &sfd, sizeof(sfd));
1601
1602     msg.msg_control = cmsg;
1603     msg.msg_controllen = cmsg->cmsg_len;
1604
1605     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1606                  "Writing message to %d, passing sd:  %d", sconf->output, sfd);
1607
1608     if ((rv = sendmsg(sconf->output, &msg, 0)) == -1) {
1609         apr_pool_destroy(r->pool);
1610         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1611                  "Writing message failed %d %d", rv, errno);
1612         return -1;
1613     }
1614
1615     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1616                  "Writing message succeeded %d", rv);
1617
1618     apr_pool_destroy(r->pool);
1619     return 1;
1620 }
1621
1622 static char *make_perchild_socket(const char *fullsockname, int sd[2])
1623 {
1624     socketpair(PF_UNIX, SOCK_STREAM, 0, sd);
1625     return NULL;
1626 }
1627
1628 static int perchild_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
1629 {
1630     int i;
1631     server_rec *sr;
1632     perchild_server_conf *sconf;
1633     int def_sd[2];
1634
1635     def_sd[0] = -1;
1636     def_sd[1] = -1;
1637
1638     for (sr = s; sr; sr = sr->next) {
1639         sconf = (perchild_server_conf *)ap_get_module_config(sr->module_config,
1640                                                       &mpm_perchild_module);
1641
1642         if (sconf->input == -1) {
1643             sconf->fullsockname = apr_pstrcat(sr->process->pool, 
1644                                              sconf->sockname, ".DEFAULT", NULL);
1645             if (def_sd[0] == -1) {
1646                 if (!make_perchild_socket(sconf->fullsockname, def_sd)) {
1647                     /* log error */
1648                 }
1649             }
1650             sconf->input = def_sd[0];
1651             sconf->output = def_sd[1];
1652         }
1653     }
1654
1655     for (i = 0; i < num_daemons; i++) {
1656         if (child_info_table[i].uid == -1) {
1657             child_info_table[i].input = def_sd[0];
1658             child_info_table[i].output = def_sd[1];
1659         }
1660     }
1661
1662     thread_socket_table = (int *)apr_pcalloc(p, thread_limit * sizeof(int));
1663     for (i = 0; i < thread_limit; i++) {
1664         thread_socket_table[i] = AP_PERCHILD_THISCHILD;
1665     }
1666     ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable));
1667
1668     return OK;
1669 }
1670
1671 static int perchild_post_read(request_rec *r)
1672 {
1673     int thread_num = r->connection->id % thread_limit;
1674     perchild_server_conf *sconf = (perchild_server_conf *)
1675                             ap_get_module_config(r->server->module_config, 
1676                                                  &mpm_perchild_module);
1677
1678     if (thread_socket_table[thread_num] != AP_PERCHILD_THISCHILD) {
1679         apr_socket_t *csd = NULL;
1680
1681         apr_os_sock_put(&csd, &thread_socket_table[thread_num], 
1682                         r->connection->pool);
1683         ap_sock_disable_nagle(csd);
1684         ap_set_module_config(r->connection->conn_config, &core_module, csd);
1685         return OK;
1686     }
1687     else {
1688         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1689                      "Determining if request should be passed. "
1690                      "Child Num: %d, SD: %d, sd from table: %d, hostname from server: %s", child_num, 
1691                      sconf->input, child_info_table[child_num].input, 
1692                      r->server->server_hostname);
1693         /* sconf is the server config for this vhost, so if our socket
1694          * is not the same that was set in the config, then the request
1695          * needs to be passed to another child. */
1696         if (sconf->input != child_info_table[child_num].input) {
1697             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
1698                          "Passing request.");
1699             if (pass_request(r) == -1) {
1700                 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
1701                              ap_server_conf, "Could not pass request to proper "
1702                              "child, request will not be honored.");
1703             }
1704             longjmp(jmpbuffer, 1); 
1705         }
1706         return OK;
1707     }
1708     return OK;
1709 }
1710
1711 static void perchild_hooks(apr_pool_t *p)
1712 {
1713     /* The perchild open_logs phase must run before the core's, or stderr
1714      * will be redirected to a file, and the messages won't print to the
1715      * console.
1716      */
1717     static const char *const aszSucc[] = {"core.c", NULL};
1718     one_process = 0;
1719
1720     ap_hook_open_logs(perchild_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
1721     ap_hook_pre_config(perchild_pre_config, NULL, NULL, APR_HOOK_MIDDLE); 
1722     ap_hook_post_config(perchild_post_config, NULL, NULL, APR_HOOK_MIDDLE); 
1723
1724     /* Both of these must be run absolutely first.  If this request isn't for 
1725      * this server then we need to forward it to the proper child.  No sense
1726      * tying up this server running more post_read request hooks if it is
1727      * just going to be forwarded along.  The process_connection hook allows
1728      * perchild to receive the passed request correctly, by automatically
1729      * filling in the core_input_filter's ctx pointer.
1730      */
1731     ap_hook_post_read_request(perchild_post_read, NULL, NULL,
1732                               APR_HOOK_REALLY_FIRST);
1733     ap_hook_process_connection(perchild_process_connection, NULL, NULL, 
1734                                APR_HOOK_REALLY_FIRST);
1735 }
1736
1737 static const char *set_num_daemons(cmd_parms *cmd, void *dummy,
1738                                    const char *arg) 
1739 {
1740     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1741     if (err != NULL) {
1742         return err;
1743     }
1744
1745     num_daemons = atoi(arg);
1746     if (num_daemons > server_limit) {
1747        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1748                     "WARNING: NumServers of %d exceeds ServerLimit value "
1749                     "of %d servers,", num_daemons, server_limit);
1750        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1751                     " lowering NumServers to %d.  To increase, please "
1752                     "see the", server_limit);
1753        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1754                     " ServerLimit directive.");
1755        num_daemons = server_limit;
1756     } 
1757     else if (num_daemons < 1) {
1758         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1759                      "WARNING: Require NumServers > 0, setting to 1");
1760         num_daemons = 1;
1761     }
1762     return NULL;
1763 }
1764
1765 static const char *set_threads_to_start(cmd_parms *cmd, void *dummy,
1766                                         const char *arg) 
1767 {
1768     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1769     if (err != NULL) {
1770         return err;
1771     }
1772
1773     threads_to_start = atoi(arg);
1774     if (threads_to_start > thread_limit) {
1775         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1776                      "WARNING: StartThreads of %d exceeds ThreadLimit value"
1777                      " of %d threads,", threads_to_start,
1778                      thread_limit);
1779         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1780                      " lowering StartThreads to %d. To increase, please"
1781                      " see the", thread_limit);
1782         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1783                      " ThreadLimit directive.");
1784     }
1785     else if (threads_to_start < 1) {
1786         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1787                      "WARNING: Require StartThreads > 0, setting to 1");
1788         threads_to_start = 1;
1789     }
1790     return NULL;
1791 }
1792
1793 static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
1794                                          const char *arg)
1795 {
1796     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1797     if (err != NULL) {
1798         return err;
1799     }
1800
1801     min_spare_threads = atoi(arg);
1802     if (min_spare_threads <= 0) {
1803        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1804                     "WARNING: detected MinSpareThreads set to non-positive.");
1805        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1806                     "Resetting to 1 to avoid almost certain Apache failure.");
1807        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1808                     "Please read the documentation.");
1809        min_spare_threads = 1;
1810     }
1811        
1812     return NULL;
1813 }
1814
1815 static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
1816                                          const char *arg)
1817 {
1818     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1819     if (err != NULL) {
1820         return err;
1821     }
1822
1823     max_spare_threads = atoi(arg);
1824     if (max_spare_threads >= thread_limit) {
1825        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1826                     "WARNING: detected MinSpareThreads set higher than");
1827        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1828                     "ThreadLimit. Resetting to %d", thread_limit);
1829        max_spare_threads = thread_limit;
1830     }
1831     return NULL;
1832 }
1833
1834 static const char *set_max_threads(cmd_parms *cmd, void *dummy, const char *arg)
1835 {
1836     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1837     if (err != NULL) {
1838         return err;
1839     }
1840
1841     max_threads = atoi(arg);
1842     if (max_threads > thread_limit) {
1843        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1844                     "WARNING: detected MaxThreadsPerChild set higher than");
1845        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1846                     "ThreadLimit. Resetting to %d", thread_limit);
1847        max_threads = thread_limit;
1848     }
1849     return NULL;
1850 }
1851
1852 static const char *set_child_per_uid(cmd_parms *cmd, void *dummy, const char *u,
1853                                      const char *g, const char *num)
1854 {
1855     int i;
1856     int max_this_time = atoi(num) + curr_child_num;
1857     
1858
1859     for (i = curr_child_num; i < max_this_time; i++, curr_child_num++) {
1860         if (i > num_daemons) {
1861             return "Trying to use more child ID's than NumServers.  Increase "
1862                    "NumServers in your config file.";
1863         }
1864     
1865         child_info_table[i].uid = ap_uname2id(u);
1866         child_info_table[i].gid = ap_gname2id(g); 
1867
1868 #ifndef BIG_SECURITY_HOLE
1869         if (child_info_table[i].uid == 0 || child_info_table[i].gid == 0) {
1870             return "Assigning root user/group to a child.";
1871         }
1872 #endif
1873     }
1874     return NULL;
1875 }
1876
1877 static const char *assign_childuid(cmd_parms *cmd, void *dummy, const char *uid,
1878                                    const char *gid)
1879 {
1880     int i;
1881     int matching = 0;
1882     int u = ap_uname2id(uid);
1883     int g = ap_gname2id(gid);
1884     const char *errstr;
1885     int socks[2];
1886     perchild_server_conf *sconf = (perchild_server_conf *)
1887                             ap_get_module_config(cmd->server->module_config, 
1888                                                  &mpm_perchild_module);
1889
1890     sconf->fullsockname = apr_pstrcat(cmd->pool, sconf->sockname, ".", uid,
1891                                       ":", gid, NULL);
1892
1893     if ((errstr = make_perchild_socket(sconf->fullsockname, socks))) {
1894         return errstr;
1895     }
1896
1897     sconf->input = socks[0]; 
1898     sconf->output = socks[1];
1899
1900     for (i = 0; i < num_daemons; i++) {
1901         if (u == child_info_table[i].uid && g == child_info_table[i].gid) {
1902             child_info_table[i].input = sconf->input;
1903             child_info_table[i].output = sconf->output;
1904             matching++;
1905             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, 
1906                          "filling out child_info_table; UID: %d, GID: %d, "
1907                          "SD: %d %d, OUTPUT: %d %d, Child Num: %d", 
1908                          child_info_table[i].uid, child_info_table[i].gid, 
1909                          sconf->input, child_info_table[i].input, sconf->output,
1910                          child_info_table[i].output, i);
1911         }
1912     }
1913
1914     if (!matching) {
1915         return "Unable to find process with matching uid/gid.";
1916     }
1917     return NULL;
1918 }
1919
1920 static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) 
1921 {
1922     int tmp_server_limit;
1923     
1924     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1925     if (err != NULL) {
1926         return err;
1927     }
1928
1929     tmp_server_limit = atoi(arg);
1930     /* you cannot change ServerLimit across a restart; ignore
1931      * any such attempts
1932      */
1933     if (first_server_limit &&
1934         tmp_server_limit != server_limit) {
1935         /* how do we log a message?  the error log is a bit bucket at this
1936          * point; we'll just have to set a flag so that ap_mpm_run()
1937          * logs a warning later
1938          */
1939         changed_limit_at_restart = 1;
1940         return NULL;
1941     }
1942     server_limit = tmp_server_limit;
1943     
1944     if (server_limit > MAX_SERVER_LIMIT) {
1945        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1946                     "WARNING: ServerLimit of %d exceeds compile time limit "
1947                     "of %d servers,", server_limit, MAX_SERVER_LIMIT);
1948        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1949                     " lowering ServerLimit to %d.", MAX_SERVER_LIMIT);
1950        server_limit = MAX_SERVER_LIMIT;
1951     } 
1952     else if (server_limit < 1) {
1953         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1954                      "WARNING: Require ServerLimit > 0, setting to 1");
1955         server_limit = 1;
1956     }
1957     return NULL;
1958 }
1959
1960 static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) 
1961 {
1962     int tmp_thread_limit;
1963     
1964     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1965     if (err != NULL) {
1966         return err;
1967     }
1968
1969     tmp_thread_limit = atoi(arg);
1970     /* you cannot change ThreadLimit across a restart; ignore
1971      * any such attempts
1972      */
1973     if (first_thread_limit &&
1974         tmp_thread_limit != thread_limit) {
1975         /* how do we log a message?  the error log is a bit bucket at this
1976          * point; we'll just have to set a flag so that ap_mpm_run()
1977          * logs a warning later
1978          */
1979         changed_limit_at_restart = 1;
1980         return NULL;
1981     }
1982     thread_limit = tmp_thread_limit;
1983     
1984     if (thread_limit > MAX_THREAD_LIMIT) {
1985        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1986                     "WARNING: ThreadLimit of %d exceeds compile time limit "
1987                     "of %d servers,", thread_limit, MAX_THREAD_LIMIT);
1988        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1989                     " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT);
1990        thread_limit = MAX_THREAD_LIMIT;
1991     } 
1992     else if (thread_limit < 1) {
1993         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
1994                      "WARNING: Require ThreadLimit > 0, setting to 1");
1995         thread_limit = 1;
1996     }
1997     return NULL;
1998 }
1999
2000 static const command_rec perchild_cmds[] = {
2001 UNIX_DAEMON_COMMANDS,
2002 LISTEN_COMMANDS,
2003 AP_INIT_TAKE1("NumServers", set_num_daemons, NULL, RSRC_CONF,
2004               "Number of children alive at the same time"),
2005 AP_INIT_TAKE1("StartThreads", set_threads_to_start, NULL, RSRC_CONF,
2006               "Number of threads each child creates"),
2007 AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
2008               "Minimum number of idle threads per child, to handle "
2009               "request spikes"),
2010 AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
2011               "Maximum number of idle threads per child"),
2012 AP_INIT_TAKE1("MaxThreadsPerChild", set_max_threads, NULL, RSRC_CONF,
2013               "Maximum number of threads per child"),
2014 AP_INIT_TAKE3("ChildperUserID", set_child_per_uid, NULL, RSRC_CONF,
2015               "Specify a User and Group for a specific child process."),
2016 AP_INIT_TAKE2("AssignUserID", assign_childuid, NULL, RSRC_CONF,
2017               "Tie a virtual host to a specific child process."),
2018 AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
2019               "Maximum value of NumServers for this run of Apache"),
2020 AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
2021               "Maximum worker threads in a server for this run of Apache"),
2022 { NULL }
2023 };
2024
2025 static void *perchild_create_config(apr_pool_t *p, server_rec *s)
2026 {
2027     perchild_server_conf *c = (perchild_server_conf *)
2028                                   apr_pcalloc(p, sizeof(perchild_server_conf));
2029
2030     c->input = -1;
2031     c->output = -1;
2032     return c;
2033 }
2034
2035 module AP_MODULE_DECLARE_DATA mpm_perchild_module = {
2036     MPM20_MODULE_STUFF,
2037     ap_mpm_rewrite_args,        /* hook to run before apache parses args */
2038     NULL,                       /* create per-directory config structure */
2039     NULL,                       /* merge per-directory config structures */
2040     perchild_create_config,     /* create per-server config structure */
2041     NULL,                       /* merge per-server config structures */
2042     perchild_cmds,              /* command apr_table_t */
2043     perchild_hooks              /* register_hooks */
2044 };
2045