]> granicus.if.org Git - apache/blob - server/mpm/prefork/prefork.c
Use new parameter orders.
[apache] / server / mpm / prefork / prefork.c
1 /* ====================================================================
2  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the Apache Group
19  *    for use in the Apache HTTP server project (http://www.apache.org/)."
20  *
21  * 4. The names "Apache Server" and "Apache Group" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    apache@apache.org.
25  *
26  * 5. Products derived from this software may not be called "Apache"
27  *    nor may "Apache" appear in their names without prior written
28  *    permission of the Apache Group.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the Apache Group
33  *    for use in the Apache HTTP server project (http://www.apache.org/)."
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Group and was originally based
51  * on public domain software written at the National Center for
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53  * For more information on the Apache Group and the Apache HTTP server
54  * project, please see <http://www.apache.org/>.
55  *
56  */
57
58 /*
59  * httpd.c: simple http daemon for answering WWW file requests
60  *
61  * 
62  * 03-21-93  Rob McCool wrote original code (up to NCSA HTTPd 1.3)
63  * 
64  * 03-06-95  blong
65  *  changed server number for child-alone processes to 0 and changed name
66  *   of processes
67  *
68  * 03-10-95  blong
69  *      Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) 
70  *      including set group before fork, and call gettime before to fork
71  *      to set up libraries.
72  *
73  * 04-14-95  rst / rh
74  *      Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
75  *      Apache server, and also to have child processes do accept() directly.
76  *
77  * April-July '95 rst
78  *      Extensive rework for Apache.
79  */
80
81 /* TODO: this is a cobbled together prefork MPM example... it should mostly
82  * TODO: behave like apache-1.3... here's a short list of things I think
83  * TODO: need cleaning up still:
84  * TODO: - use ralf's mm stuff for the shared mem and mutexes
85  * TODO: - clean up scoreboard stuff when we figure out how to do it in 2.0
86  */
87
88 #define CORE_PRIVATE
89
90 #include "apr_portable.h"
91 #include "httpd.h"
92 #include "mpm_default.h"
93 #include "http_main.h"
94 #include "http_log.h"
95 #include "http_config.h"
96 #include "http_core.h"          /* for get_remote_host */
97 #include "http_connection.h"
98 #include "scoreboard.h"
99 #include "ap_mpm.h"
100 #include "unixd.h"
101 #include "iol_socket.h"
102 #include "ap_listen.h"
103 #ifdef USE_SHMGET_SCOREBOARD
104 #include <sys/types.h>
105 #include <sys/ipc.h>
106 #include <sys/shm.h>
107 #endif
108
109 #ifdef HAVE_BSTRING_H
110 #include <bstring.h>            /* for IRIX, FD_SET calls bzero() */
111 #endif
112
113 /* config globals */
114
115 static int ap_max_requests_per_child=0;
116 static char *ap_pid_fname=NULL;
117 static char *ap_scoreboard_fname=NULL;
118 static char *ap_lock_fname;
119 static char *ap_server_argv0=NULL;
120 static int ap_daemons_to_start=0;
121 static int ap_daemons_min_free=0;
122 static int ap_daemons_max_free=0;
123 static int ap_daemons_limit=0;
124 static time_t ap_restart_time=0;
125 static int ap_extended_status = 0;
126
127 /*
128  * The max child slot ever assigned, preserved across restarts.  Necessary
129  * to deal with MaxClients changes across SIGUSR1 restarts.  We use this
130  * value to optimize routines that have to scan the entire scoreboard.
131  */
132 static int max_daemons_limit = -1;
133
134 static char ap_coredump_dir[MAX_STRING_LEN];
135
136 /* *Non*-shared http_main globals... */
137
138 static server_rec *server_conf;
139 static ap_socket_t *sd;
140 static fd_set listenfds;
141 static int listenmaxfd;
142
143 /* one_process --- debugging mode variable; can be set from the command line
144  * with the -X flag.  If set, this gets you the child_main loop running
145  * in the process which originally started up (no detach, no make_child),
146  * which is a pretty nice debugging environment.  (You'll get a SIGHUP
147  * early in standalone_main; just continue through.  This is the server
148  * trying to kill off any child processes which it might have lying
149  * around --- Apache doesn't keep track of their pids, it just sends
150  * SIGHUP to the process group, ignoring it in the root process.
151  * Continue through and you'll be fine.).
152  */
153
154 static int one_process = 0;
155
156 #ifdef HAS_OTHER_CHILD
157 /* used to maintain list of children which aren't part of the scoreboard */
158 typedef struct other_child_rec other_child_rec;
159 struct other_child_rec {
160     other_child_rec *next;
161     int pid;
162     void (*maintenance) (int, void *, ap_wait_t);
163     void *data;
164     int write_fd;
165 };
166 static other_child_rec *other_children;
167 #endif
168
169 static ap_context_t *pconf;             /* Pool for config stuff */
170 static ap_context_t *pchild;            /* Pool for httpd child stuff */
171
172 static int my_pid;      /* it seems silly to call getpid all the time */
173 #ifndef MULTITHREAD
174 static int my_child_num;
175 #endif
176
177 #ifdef TPF
178 int tpf_child = 0;
179 char tpf_server_name[INETD_SERVNAME_LENGTH+1];
180 #endif /* TPF */
181
182 static scoreboard *ap_scoreboard_image = NULL;
183
184 #ifdef GPROF
185 /* 
186  * change directory for gprof to plop the gmon.out file
187  * configure in httpd.conf:
188  * GprofDir logs/   -> $ServerRoot/logs/gmon.out
189  * GprofDir logs/%  -> $ServerRoot/logs/gprof.$pid/gmon.out
190  */
191 static void chdir_for_gprof(void)
192 {
193     core_server_config *sconf = 
194         ap_get_module_config(server_conf->module_config, &core_module);    
195     char *dir = sconf->gprof_dir;
196
197     if(dir) {
198         char buf[512];
199         int len = strlen(sconf->gprof_dir) - 1;
200         if(*(dir + len) == '%') {
201             dir[len] = '\0';
202             ap_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid());
203         } 
204         dir = ap_server_root_relative(pconf, buf[0] ? buf : dir);
205         if(mkdir(dir, 0755) < 0 && errno != EEXIST) {
206             ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
207                          "gprof: error creating directory %s", dir);
208         }
209     }
210     else {
211         dir = ap_server_root_relative(pconf, "logs");
212     }
213
214     chdir(dir);
215 }
216 #else
217 #define chdir_for_gprof()
218 #endif
219
220 /* a clean exit from a child with proper cleanup */
221 static void clean_child_exit(int code) __attribute__ ((noreturn));
222 static void clean_child_exit(int code)
223 {
224     if (pchild) {
225         ap_destroy_pool(pchild);
226     }
227     chdir_for_gprof();
228     exit(code);
229 }
230
231 #if defined(USE_FCNTL_SERIALIZED_ACCEPT) || defined(USE_FLOCK_SERIALIZED_ACCEPT)
232 static void expand_lock_fname(ap_context_t *p)
233 {
234     /* XXXX possibly bogus cast */
235     ap_lock_fname = ap_psprintf(p, "%s.%lu",
236         ap_server_root_relative(p, ap_lock_fname), (unsigned long)getpid());
237 }
238 #endif
239
240 #if defined (USE_USLOCK_SERIALIZED_ACCEPT)
241
242 #include <ulocks.h>
243
244 static ulock_t uslock = NULL;
245
246 #define accept_mutex_child_init(x)
247
248 static void accept_mutex_init(ap_context_t *p)
249 {
250     ptrdiff_t old;
251     usptr_t *us;
252
253
254     /* default is 8, allocate enough for all the children plus the parent */
255     if ((old = usconfig(CONF_INITUSERS, HARD_SERVER_LIMIT + 1)) == -1) {
256         perror("usconfig(CONF_INITUSERS)");
257         exit(-1);
258     }
259
260     if ((old = usconfig(CONF_LOCKTYPE, US_NODEBUG)) == -1) {
261         perror("usconfig(CONF_LOCKTYPE)");
262         exit(-1);
263     }
264     if ((old = usconfig(CONF_ARENATYPE, US_SHAREDONLY)) == -1) {
265         perror("usconfig(CONF_ARENATYPE)");
266         exit(-1);
267     }
268     if ((us = usinit("/dev/zero")) == NULL) {
269         perror("usinit");
270         exit(-1);
271     }
272
273     if ((uslock = usnewlock(us)) == NULL) {
274         perror("usnewlock");
275         exit(-1);
276     }
277 }
278
279 static void accept_mutex_on(void)
280 {
281     switch (ussetlock(uslock)) {
282     case 1:
283         /* got lock */
284         break;
285     case 0:
286         fprintf(stderr, "didn't get lock\n");
287         clean_child_exit(APEXIT_CHILDFATAL);
288     case -1:
289         perror("ussetlock");
290         clean_child_exit(APEXIT_CHILDFATAL);
291     }
292 }
293
294 static void accept_mutex_off(void)
295 {
296     if (usunsetlock(uslock) == -1) {
297         perror("usunsetlock");
298         clean_child_exit(APEXIT_CHILDFATAL);
299     }
300 }
301
302 #elif defined (USE_PTHREAD_SERIALIZED_ACCEPT)
303
304 /* This code probably only works on Solaris ... but it works really fast
305  * on Solaris.  Note that pthread mutexes are *NOT* released when a task
306  * dies ... the task has to free it itself.  So we block signals and
307  * try to be nice about releasing the mutex.
308  */
309
310 #include <pthread.h>
311
312 static pthread_mutex_t *accept_mutex = (void *)(caddr_t) -1;
313 static int have_accept_mutex;
314 static sigset_t accept_block_mask;
315 static sigset_t accept_previous_mask;
316
317 static void accept_mutex_child_cleanup(void *foo)
318 {
319     if (accept_mutex != (void *)(caddr_t)-1
320         && have_accept_mutex) {
321         pthread_mutex_unlock(accept_mutex);
322     }
323 }
324
325 static void accept_mutex_child_init(ap_context_t *p)
326 {
327     ap_register_cleanup(p, NULL, accept_mutex_child_cleanup, ap_null_cleanup);
328 }
329
330 static void accept_mutex_cleanup(void *foo)
331 {
332     if (accept_mutex != (void *)(caddr_t)-1
333         && munmap((caddr_t) accept_mutex, sizeof(*accept_mutex))) {
334         perror("munmap");
335     }
336     accept_mutex = (void *)(caddr_t)-1;
337 }
338
339 static void accept_mutex_init(ap_context_t *p)
340 {
341     pthread_mutexattr_t mattr;
342     int fd;
343
344     fd = open("/dev/zero", O_RDWR);
345     if (fd == -1) {
346         perror("open(/dev/zero)");
347         exit(APEXIT_INIT);
348     }
349     accept_mutex = (pthread_mutex_t *) mmap((caddr_t) 0, sizeof(*accept_mutex),
350                                  PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
351     if (accept_mutex == (void *) (caddr_t) - 1) {
352         perror("mmap");
353         exit(APEXIT_INIT);
354     }
355     close(fd);
356     if ((errno = pthread_mutexattr_init(&mattr))) {
357         perror("pthread_mutexattr_init");
358         exit(APEXIT_INIT);
359     }
360     if ((errno = pthread_mutexattr_setpshared(&mattr,
361                                                 PTHREAD_PROCESS_SHARED))) {
362         perror("pthread_mutexattr_setpshared");
363         exit(APEXIT_INIT);
364     }
365     if ((errno = pthread_mutex_init(accept_mutex, &mattr))) {
366         perror("pthread_mutex_init");
367         exit(APEXIT_INIT);
368     }
369     sigfillset(&accept_block_mask);
370     sigdelset(&accept_block_mask, SIGHUP);
371     sigdelset(&accept_block_mask, SIGTERM);
372     sigdelset(&accept_block_mask, SIGUSR1);
373     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
374 }
375
376 static void accept_mutex_on(void)
377 {
378     int err;
379
380     if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) {
381         perror("sigprocmask(SIG_BLOCK)");
382         clean_child_exit(APEXIT_CHILDFATAL);
383     }
384     if ((err = pthread_mutex_lock(accept_mutex))) {
385         errno = err;
386         perror("pthread_mutex_lock");
387         clean_child_exit(APEXIT_CHILDFATAL);
388     }
389     have_accept_mutex = 1;
390 }
391
392 static void accept_mutex_off(void)
393 {
394     int err;
395
396     if ((err = pthread_mutex_unlock(accept_mutex))) {
397         errno = err;
398         perror("pthread_mutex_unlock");
399         clean_child_exit(APEXIT_CHILDFATAL);
400     }
401     /* There is a slight race condition right here... if we were to die right
402      * now, we'd do another pthread_mutex_unlock.  Now, doing that would let
403      * another process into the mutex.  pthread mutexes are designed to be
404      * fast, as such they don't have protection for things like testing if the
405      * thread owning a mutex is actually unlocking it (or even any way of
406      * testing who owns the mutex).
407      *
408      * If we were to unset have_accept_mutex prior to releasing the mutex
409      * then the race could result in the server unable to serve hits.  Doing
410      * it this way means that the server can continue, but an additional
411      * child might be in the critical section ... at least it's still serving
412      * hits.
413      */
414     have_accept_mutex = 0;
415     if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) {
416         perror("sigprocmask(SIG_SETMASK)");
417         clean_child_exit(1);
418     }
419 }
420
421 #elif defined (USE_SYSVSEM_SERIALIZED_ACCEPT)
422
423 #include <sys/types.h>
424 #include <sys/ipc.h>
425 #include <sys/sem.h>
426
427 #ifdef NEED_UNION_SEMUN
428 /* it makes no sense, but this isn't defined on solaris */
429 union semun {
430     long val;
431     struct semid_ds *buf;
432     ushort *array;
433 };
434
435 #endif
436
437 static int sem_id = -1;
438 static struct sembuf op_on;
439 static struct sembuf op_off;
440
441 /* We get a random semaphore ... the lame sysv semaphore interface
442  * means we have to be sure to clean this up or else we'll leak
443  * semaphores.
444  */
445 static void accept_mutex_cleanup(void *foo)
446 {
447     union semun ick;
448
449     if (sem_id < 0)
450         return;
451     /* this is ignored anyhow */
452     ick.val = 0;
453     semctl(sem_id, 0, IPC_RMID, ick);
454 }
455
456 #define accept_mutex_child_init(x)
457
458 static void accept_mutex_init(ap_context_t *p)
459 {
460     union semun ick;
461     struct semid_ds buf;
462
463     /* acquire the semaphore */
464     sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
465     if (sem_id < 0) {
466         perror("semget");
467         exit(APEXIT_INIT);
468     }
469     ick.val = 1;
470     if (semctl(sem_id, 0, SETVAL, ick) < 0) {
471         perror("semctl(SETVAL)");
472         exit(APEXIT_INIT);
473     }
474     if (!getuid()) {
475         /* restrict it to use only by the appropriate user_id ... not that this
476          * stops CGIs from acquiring it and dinking around with it.
477          */
478         buf.sem_perm.uid = unixd_config.user_id;
479         buf.sem_perm.gid = unixd_config.group_id;
480         buf.sem_perm.mode = 0600;
481         ick.buf = &buf;
482         if (semctl(sem_id, 0, IPC_SET, ick) < 0) {
483             perror("semctl(IPC_SET)");
484             exit(APEXIT_INIT);
485         }
486     }
487     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
488
489     /* pre ap_context_t nitialize these */
490     op_on.sem_num = 0;
491     op_on.sem_op = -1;
492     op_on.sem_flg = SEM_UNDO;
493     op_off.sem_num = 0;
494     op_off.sem_op = 1;
495     op_off.sem_flg = SEM_UNDO;
496 }
497
498 static void accept_mutex_on(void)
499 {
500     while (semop(sem_id, &op_on, 1) < 0) {
501         if (errno != EINTR) {
502             perror("accept_mutex_on");
503             clean_child_exit(APEXIT_CHILDFATAL);
504         }
505     }
506 }
507
508 static void accept_mutex_off(void)
509 {
510     while (semop(sem_id, &op_off, 1) < 0) {
511         if (errno != EINTR) {
512             perror("accept_mutex_off");
513             clean_child_exit(APEXIT_CHILDFATAL);
514         }
515     }
516 }
517
518 #elif defined(USE_FCNTL_SERIALIZED_ACCEPT)
519 static struct flock lock_it;
520 static struct flock unlock_it;
521
522 static int lock_fd = -1;
523
524 #define accept_mutex_child_init(x)
525
526 /*
527  * Initialize mutex lock.
528  * Must be safe to call this on a restart.
529  */
530 static void accept_mutex_init(ap_context_t *p)
531 {
532     ap_file_t *tempfile;
533     lock_it.l_whence = SEEK_SET;        /* from current point */
534     lock_it.l_start = 0;                /* -"- */
535     lock_it.l_len = 0;                  /* until end of file */
536     lock_it.l_type = F_WRLCK;           /* set exclusive/write lock */
537     lock_it.l_pid = 0;                  /* pid not actually interesting */
538     unlock_it.l_whence = SEEK_SET;      /* from current point */
539     unlock_it.l_start = 0;              /* -"- */
540     unlock_it.l_len = 0;                /* until end of file */
541     unlock_it.l_type = F_UNLCK;         /* set exclusive/write lock */
542     unlock_it.l_pid = 0;                /* pid not actually interesting */
543
544     expand_lock_fname(p);
545     ap_open(&tempfile, p, ap_lock_fname, APR_CREATE | APR_WRITE | APR_EXCL,
546             APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD);
547     ap_get_os_file(tempfile, &lock_fd);
548     if (lock_fd == -1) {
549         perror("open");
550         fprintf(stderr, "Cannot open lock file: %s\n", ap_lock_fname);
551         exit(APEXIT_INIT);
552     }
553     unlink(ap_lock_fname);
554 }
555
556 static void accept_mutex_on(void)
557 {
558     int ret;
559
560     while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR) {
561         /* nop */
562     }
563
564     if (ret < 0) {
565         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
566                     "fcntl: F_SETLKW: Error getting accept lock, exiting!  "
567                     "Perhaps you need to use the LockFile directive to place "
568                     "your lock file on a local disk!");
569         clean_child_exit(APEXIT_CHILDFATAL);
570     }
571 }
572
573 static void accept_mutex_off(void)
574 {
575     int ret;
576
577     while ((ret = fcntl(lock_fd, F_SETLKW, &unlock_it)) < 0 && errno == EINTR) {
578         /* nop */
579     }
580     if (ret < 0) {
581         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
582                     "fcntl: F_SETLKW: Error freeing accept lock, exiting!  "
583                     "Perhaps you need to use the LockFile directive to place "
584                     "your lock file on a local disk!");
585         clean_child_exit(APEXIT_CHILDFATAL);
586     }
587 }
588
589 #elif defined(USE_FLOCK_SERIALIZED_ACCEPT)
590
591 static int lock_fd = -1;
592
593 static ap_status_t accept_mutex_cleanup(void *foo)
594 {
595     unlink(ap_lock_fname);
596
597     return APR_SUCCESS;
598 }
599
600 /*
601  * Initialize mutex lock.
602  * Done by each child at it's birth
603  */
604 static void accept_mutex_child_init(ap_context_t *p)
605 {
606     ap_file_t *tempfile;
607
608     ap_open(&tempfile, p, ap_lock_fname, APR_WRITE, APR_UREAD|APR_UWRITE);
609     if (!tempfile) {
610         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
611                     "Child cannot open lock file: %s", ap_lock_fname);
612         clean_child_exit(APEXIT_CHILDINIT);
613     }
614     ap_get_os_file(tempfile, &lock_fd);
615 }
616
617 /*
618  * Initialize mutex lock.
619  * Must be safe to call this on a restart.
620  */
621 static void accept_mutex_init(ap_context_t *p)
622 {
623     ap_file_t *tempfile;
624
625     expand_lock_fname(p);
626     unlink(ap_lock_fname);
627     ap_open(&tempfile, p, ap_lock_fname, APR_CREATE|APR_WRITE|APR_EXCL,
628             APR_UREAD|APR_UWRITE);
629     if (!tempfile) {
630         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
631                     "Parent cannot open lock file: %s", ap_lock_fname);
632         exit(APEXIT_INIT);
633     }
634     ap_get_os_file(tempfile, &lock_fd);
635     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
636 }
637
638 static void accept_mutex_on(void)
639 {
640     int ret;
641
642     while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR)
643         continue;
644
645     if (ret < 0) {
646         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
647                     "flock: LOCK_EX: Error getting accept lock. Exiting!");
648         clean_child_exit(APEXIT_CHILDFATAL);
649     }
650 }
651
652 static void accept_mutex_off(void)
653 {
654     if (flock(lock_fd, LOCK_UN) < 0) {
655         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
656                     "flock: LOCK_UN: Error freeing accept lock. Exiting!");
657         clean_child_exit(APEXIT_CHILDFATAL);
658     }
659 }
660
661 #elif defined(USE_OS2SEM_SERIALIZED_ACCEPT)
662
663 static HMTX lock_sem = -1;
664
665 static void accept_mutex_cleanup(void *foo)
666 {
667     DosReleaseMutexSem(lock_sem);
668     DosCloseMutexSem(lock_sem);
669 }
670
671 /*
672  * Initialize mutex lock.
673  * Done by each child at it's birth
674  */
675 static void accept_mutex_child_init(ap_context_t *p)
676 {
677     int rc = DosOpenMutexSem(NULL, &lock_sem);
678
679     if (rc != 0) {
680         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
681                     "Child cannot open lock semaphore, rc=%d", rc);
682         clean_child_exit(APEXIT_CHILDINIT);
683     } else {
684         ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
685     }
686 }
687
688 /*
689  * Initialize mutex lock.
690  * Must be safe to call this on a restart.
691  */
692 static void accept_mutex_init(ap_context_t *p)
693 {
694     int rc = DosCreateMutexSem(NULL, &lock_sem, DC_SEM_SHARED, FALSE);
695
696     if (rc != 0) {
697         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
698                     "Parent cannot create lock semaphore, rc=%d", rc);
699         exit(APEXIT_INIT);
700     }
701
702     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
703 }
704
705 static void accept_mutex_on(void)
706 {
707     int rc = DosRequestMutexSem(lock_sem, SEM_INDEFINITE_WAIT);
708
709     if (rc != 0) {
710         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
711                     "OS2SEM: Error %d getting accept lock. Exiting!", rc);
712         clean_child_exit(APEXIT_CHILDFATAL);
713     }
714 }
715
716 static void accept_mutex_off(void)
717 {
718     int rc = DosReleaseMutexSem(lock_sem);
719     
720     if (rc != 0) {
721         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
722                     "OS2SEM: Error %d freeing accept lock. Exiting!", rc);
723         clean_child_exit(APEXIT_CHILDFATAL);
724     }
725 }
726
727 #elif defined(USE_TPF_CORE_SERIALIZED_ACCEPT)
728
729 static int tpf_core_held;
730
731 static void accept_mutex_cleanup(void *foo)
732 {
733     if(tpf_core_held)
734         coruc(RESOURCE_KEY);
735 }
736
737 #define accept_mutex_init(x)
738
739 static void accept_mutex_child_init(ap_context_t *p)
740 {
741     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
742     tpf_core_held = 0;
743 }
744
745 static void accept_mutex_on(void)
746 {
747     corhc(RESOURCE_KEY);
748     tpf_core_held = 1;
749     ap_check_signals();
750 }
751
752 static void accept_mutex_off(void)
753 {
754     coruc(RESOURCE_KEY);
755     tpf_core_held = 0;
756     ap_check_signals();
757 }
758
759 #else
760 /* Default --- no serialization.  Other methods *could* go here,
761  * as #elifs...
762  */
763 #if !defined(MULTITHREAD)
764 /* Multithreaded systems don't complete between processes for
765  * the sockets. */
766 #define NO_SERIALIZED_ACCEPT
767 #define accept_mutex_child_init(x)
768 #define accept_mutex_init(x)
769 #define accept_mutex_on()
770 #define accept_mutex_off()
771 #endif
772 #endif
773
774 /* On some architectures it's safe to do unserialized accept()s in the single
775  * Listen case.  But it's never safe to do it in the case where there's
776  * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
777  * when it's safe in the single Listen case.
778  */
779 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
780 #define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
781 #else
782 #define SAFE_ACCEPT(stmt) do {stmt;} while(0)
783 #endif
784
785
786 /*****************************************************************
787  * dealing with other children
788  */
789
790 #ifdef HAS_OTHER_CHILD
791 API_EXPORT(void) ap_register_other_child(int pid,
792                        void (*maintenance) (int reason, void *, ap_wait_t status),
793                           void *data, int write_fd)
794 {
795     other_child_rec *ocr;
796
797     ocr = ap_palloc(pconf, sizeof(*ocr));
798     ocr->pid = pid;
799     ocr->maintenance = maintenance;
800     ocr->data = data;
801     ocr->write_fd = write_fd;
802     ocr->next = other_children;
803     other_children = ocr;
804 }
805
806 /* note that since this can be called by a maintenance function while we're
807  * scanning the other_children list, all scanners should protect themself
808  * by loading ocr->next before calling any maintenance function.
809  */
810 API_EXPORT(void) ap_unregister_other_child(void *data)
811 {
812     other_child_rec **pocr, *nocr;
813
814     for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
815         if ((*pocr)->data == data) {
816             nocr = (*pocr)->next;
817             (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
818             *pocr = nocr;
819             /* XXX: um, well we've just wasted some space in pconf ? */
820             return;
821         }
822     }
823 }
824
825 /* test to ensure that the write_fds are all still writable, otherwise
826  * invoke the maintenance functions as appropriate */
827 static void probe_writable_fds(void)
828 {
829     fd_set writable_fds;
830     int fd_max;
831     other_child_rec *ocr, *nocr;
832     struct timeval tv;
833     int rc;
834
835     if (other_children == NULL)
836         return;
837
838     fd_max = 0;
839     FD_ZERO(&writable_fds);
840     do {
841         for (ocr = other_children; ocr; ocr = ocr->next) {
842             if (ocr->write_fd == -1)
843                 continue;
844             FD_SET(ocr->write_fd, &writable_fds);
845             if (ocr->write_fd > fd_max) {
846                 fd_max = ocr->write_fd;
847             }
848         }
849         if (fd_max == 0)
850             return;
851
852         tv.tv_sec = 0;
853         tv.tv_usec = 0;
854         rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
855     } while (rc == -1 && errno == EINTR);
856
857     if (rc == -1) {
858         /* XXX: uhh this could be really bad, we could have a bad file
859          * descriptor due to a bug in one of the maintenance routines */
860         ap_log_unixerr("probe_writable_fds", "select",
861                     "could not probe writable fds", server_conf);
862         return;
863     }
864     if (rc == 0)
865         return;
866
867     for (ocr = other_children; ocr; ocr = nocr) {
868         nocr = ocr->next;
869         if (ocr->write_fd == -1)
870             continue;
871         if (FD_ISSET(ocr->write_fd, &writable_fds))
872             continue;
873         (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
874     }
875 }
876
877 /* possibly reap an other_child, return 0 if yes, -1 if not */
878 static int reap_other_child(int pid, ap_wait_t status)
879 {
880     other_child_rec *ocr, *nocr;
881
882     for (ocr = other_children; ocr; ocr = nocr) {
883         nocr = ocr->next;
884         if (ocr->pid != pid)
885             continue;
886         ocr->pid = -1;
887         (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
888         return 0;
889     }
890     return -1;
891 }
892 #endif
893
894 /*****************************************************************
895  *
896  * Dealing with the scoreboard... a lot of these variables are global
897  * only to avoid getting clobbered by the longjmp() that happens when
898  * a hard timeout expires...
899  *
900  * We begin with routines which deal with the file itself... 
901  */
902
903 #if defined(USE_OS2_SCOREBOARD)
904
905 /* The next two routines are used to access shared memory under OS/2.  */
906 /* This requires EMX v09c to be installed.                           */
907
908 caddr_t create_shared_heap(const char *name, size_t size)
909 {
910     ULONG rc;
911     void *mem;
912     Heap_t h;
913
914     rc = DosAllocSharedMem(&mem, name, size,
915                            PAG_COMMIT | PAG_READ | PAG_WRITE);
916     if (rc != 0)
917         return NULL;
918     h = _ucreate(mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED,
919                  NULL, NULL);
920     if (h == NULL)
921         DosFreeMem(mem);
922     return (caddr_t) h;
923 }
924
925 caddr_t get_shared_heap(const char *Name)
926 {
927
928     PVOID BaseAddress;          /* Pointer to the base address of
929                                    the shared memory object */
930     ULONG AttributeFlags;       /* Flags describing characteristics
931                                    of the shared memory object */
932     APIRET rc;                  /* Return code */
933
934     /* Request read and write access to */
935     /*   the shared memory object       */
936     AttributeFlags = PAG_WRITE | PAG_READ;
937
938     rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags);
939
940     if (rc != 0) {
941         printf("DosGetNamedSharedMem error: return code = %ld", rc);
942         return 0;
943     }
944
945     return BaseAddress;
946 }
947
948 static void setup_shared_mem(ap_context_t *p)
949 {
950     caddr_t m;
951
952     int rc;
953
954     m = (caddr_t) create_shared_heap("\\SHAREMEM\\SCOREBOARD", SCOREBOARD_SIZE);
955     if (m == 0) {
956         fprintf(stderr, "%s: Could not create OS/2 Shared memory pool.\n",
957                 ap_server_argv0);
958         exit(APEXIT_INIT);
959     }
960
961     rc = _uopen((Heap_t) m);
962     if (rc != 0) {
963         fprintf(stderr,
964                 "%s: Could not uopen() newly created OS/2 Shared memory pool.\n",
965                 ap_server_argv0);
966     }
967     ap_scoreboard_image = (scoreboard *) m;
968     ap_scoreboard_image->global.running_generation = 0;
969 }
970
971 static void reopen_scoreboard(ap_context_t *p)
972 {
973     caddr_t m;
974     int rc;
975
976     m = (caddr_t) get_shared_heap("\\SHAREMEM\\SCOREBOARD");
977     if (m == 0) {
978         fprintf(stderr, "%s: Could not find existing OS/2 Shared memory pool.\n",
979                 ap_server_argv0);
980         exit(APEXIT_INIT);
981     }
982
983     rc = _uopen((Heap_t) m);
984     ap_scoreboard_image = (scoreboard *) m;
985 }
986
987 #elif defined(USE_POSIX_SCOREBOARD)
988 #include <sys/mman.h>
989 /* 
990  * POSIX 1003.4 style
991  *
992  * Note 1: 
993  * As of version 4.23A, shared memory in QNX must reside under /dev/shmem,
994  * where no subdirectories allowed.
995  *
996  * POSIX shm_open() and shm_unlink() will take care about this issue,
997  * but to avoid confusion, I suggest to redefine scoreboard file name
998  * in httpd.conf to cut "logs/" from it. With default setup actual name
999  * will be "/dev/shmem/logs.apache_status". 
1000  * 
1001  * If something went wrong and Apache did not unlinked this object upon
1002  * exit, you can remove it manually, using "rm -f" command.
1003  * 
1004  * Note 2:
1005  * <sys/mman.h> in QNX defines MAP_ANON, but current implementation 
1006  * does NOT support BSD style anonymous mapping. So, the order of 
1007  * conditional compilation is important: 
1008  * this #ifdef section must be ABOVE the next one (BSD style).
1009  *
1010  * I tested this stuff and it works fine for me, but if it provides 
1011  * trouble for you, just comment out USE_MMAP_SCOREBOARD in QNX section
1012  * of ap_config.h
1013  *
1014  * June 5, 1997, 
1015  * Igor N. Kovalenko -- infoh@mail.wplus.net
1016  */
1017
1018 static void cleanup_shared_mem(void *d)
1019 {
1020     shm_unlink(ap_scoreboard_fname);
1021 }
1022
1023 static void setup_shared_mem(ap_context_t *p)
1024 {
1025     char buf[512];
1026     caddr_t m;
1027     int fd;
1028
1029     fd = shm_open(ap_scoreboard_fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1030     if (fd == -1) {
1031         ap_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard",
1032                     ap_server_argv0);
1033         perror(buf);
1034         exit(APEXIT_INIT);
1035     }
1036     if (ltrunc(fd, (off_t) SCOREBOARD_SIZE, SEEK_SET) == -1) {
1037         ap_snprintf(buf, sizeof(buf), "%s: could not ltrunc scoreboard",
1038                     ap_server_argv0);
1039         perror(buf);
1040         shm_unlink(ap_scoreboard_fname);
1041         exit(APEXIT_INIT);
1042     }
1043     if ((m = (caddr_t) mmap((caddr_t) 0,
1044                             (size_t) SCOREBOARD_SIZE, PROT_READ | PROT_WRITE,
1045                             MAP_SHARED, fd, (off_t) 0)) == (caddr_t) - 1) {
1046         ap_snprintf(buf, sizeof(buf), "%s: cannot mmap scoreboard",
1047                     ap_server_argv0);
1048         perror(buf);
1049         shm_unlink(ap_scoreboard_fname);
1050         exit(APEXIT_INIT);
1051     }
1052     close(fd);
1053     ap_register_cleanup(p, NULL, cleanup_shared_mem, ap_null_cleanup);
1054     ap_scoreboard_image = (scoreboard *) m;
1055     ap_scoreboard_image->global.running_generation = 0;
1056 }
1057
1058 static void reopen_scoreboard(ap_context_t *p)
1059 {
1060 }
1061
1062 #elif defined(USE_MMAP_SCOREBOARD)
1063
1064 static void setup_shared_mem(ap_context_t *p)
1065 {
1066     caddr_t m;
1067
1068 #if defined(MAP_ANON)
1069 /* BSD style */
1070 #ifdef CONVEXOS11
1071     /*
1072      * 9-Aug-97 - Jeff Venters (venters@convex.hp.com)
1073      * ConvexOS maps address space as follows:
1074      *   0x00000000 - 0x7fffffff : Kernel
1075      *   0x80000000 - 0xffffffff : User
1076      * Start mmapped area 1GB above start of text.
1077      *
1078      * Also, the length requires a pointer as the actual length is
1079      * returned (rounded up to a page boundary).
1080      */
1081     {
1082         unsigned len = SCOREBOARD_SIZE;
1083
1084         m = mmap((caddr_t) 0xC0000000, &len,
1085                  PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, NOFD, 0);
1086     }
1087 #elif defined(MAP_TMPFILE)
1088     {
1089         char mfile[] = "/tmp/apache_shmem_XXXX";
1090         int fd = mkstemp(mfile);
1091         if (fd == -1) {
1092             perror("open");
1093             fprintf(stderr, "%s: Could not open %s\n", ap_server_argv0, mfile);
1094             exit(APEXIT_INIT);
1095         }
1096         m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
1097                 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1098         if (m == (caddr_t) - 1) {
1099             perror("mmap");
1100             fprintf(stderr, "%s: Could not mmap %s\n", ap_server_argv0, mfile);
1101             exit(APEXIT_INIT);
1102         }
1103         close(fd);
1104         unlink(mfile);
1105     }
1106 #else
1107     m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
1108              PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
1109 #endif
1110     if (m == (caddr_t) - 1) {
1111         perror("mmap");
1112         fprintf(stderr, "%s: Could not mmap memory\n", ap_server_argv0);
1113         exit(APEXIT_INIT);
1114     }
1115 #else
1116 /* Sun style */
1117     int fd;
1118
1119     fd = open("/dev/zero", O_RDWR);
1120     if (fd == -1) {
1121         perror("open");
1122         fprintf(stderr, "%s: Could not open /dev/zero\n", ap_server_argv0);
1123         exit(APEXIT_INIT);
1124     }
1125     m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
1126              PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1127     if (m == (caddr_t) - 1) {
1128         perror("mmap");
1129         fprintf(stderr, "%s: Could not mmap /dev/zero\n", ap_server_argv0);
1130         exit(APEXIT_INIT);
1131     }
1132     close(fd);
1133 #endif
1134     ap_scoreboard_image = (scoreboard *) m;
1135     ap_scoreboard_image->global.running_generation = 0;
1136 }
1137
1138 static void reopen_scoreboard(ap_context_t *p)
1139 {
1140 }
1141
1142 #elif defined(USE_SHMGET_SCOREBOARD)
1143 static key_t shmkey = IPC_PRIVATE;
1144 static int shmid = -1;
1145
1146 static void setup_shared_mem(ap_context_t *p)
1147 {
1148     struct shmid_ds shmbuf;
1149 #ifdef MOVEBREAK
1150     char *obrk;
1151 #endif
1152
1153     if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT | SHM_R | SHM_W)) == -1) {
1154 #ifdef LINUX
1155         if (errno == ENOSYS) {
1156             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
1157                          "Your kernel was built without CONFIG_SYSVIPC\n"
1158                          "%s: Please consult the Apache FAQ for details",
1159                          ap_server_argv0);
1160         }
1161 #endif
1162         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
1163                     "could not call shmget");
1164         exit(APEXIT_INIT);
1165     }
1166
1167     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
1168                 "created shared memory segment #%d", shmid);
1169
1170 #ifdef MOVEBREAK
1171     /*
1172      * Some SysV systems place the shared segment WAY too close
1173      * to the dynamic memory break point (sbrk(0)). This severely
1174      * limits the use of malloc/sbrk in the program since sbrk will
1175      * refuse to move past that point.
1176      *
1177      * To get around this, we move the break point "way up there",
1178      * attach the segment and then move break back down. Ugly
1179      */
1180     if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) {
1181         ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1182             "sbrk() could not move break");
1183     }
1184 #endif
1185
1186 #define BADSHMAT        ((scoreboard *)(-1))
1187     if ((ap_scoreboard_image = (scoreboard *) shmat(shmid, 0, 0)) == BADSHMAT) {
1188         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, "shmat error");
1189         /*
1190          * We exit below, after we try to remove the segment
1191          */
1192     }
1193     else {                      /* only worry about permissions if we attached the segment */
1194         if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) {
1195             ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1196                 "shmctl() could not stat segment #%d", shmid);
1197         }
1198         else {
1199             shmbuf.shm_perm.uid = unixd_config.user_id;
1200             shmbuf.shm_perm.gid = unixd_config.group_id;
1201             if (shmctl(shmid, IPC_SET, &shmbuf) != 0) {
1202                 ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1203                     "shmctl() could not set segment #%d", shmid);
1204             }
1205         }
1206     }
1207     /*
1208      * We must avoid leaving segments in the kernel's
1209      * (small) tables.
1210      */
1211     if (shmctl(shmid, IPC_RMID, NULL) != 0) {
1212         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
1213                 "shmctl: IPC_RMID: could not remove shared memory segment #%d",
1214                 shmid);
1215     }
1216     if (ap_scoreboard_image == BADSHMAT)        /* now bailout */
1217         exit(APEXIT_INIT);
1218
1219 #ifdef MOVEBREAK
1220     if (obrk == (char *) -1)
1221         return;                 /* nothing else to do */
1222     if (sbrk(-(MOVEBREAK)) == (char *) -1) {
1223         ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1224             "sbrk() could not move break back");
1225     }
1226 #endif
1227     ap_scoreboard_image->global.running_generation = 0;
1228 }
1229
1230 static void reopen_scoreboard(ap_context_t *p)
1231 {
1232 }
1233
1234 #elif defined(USE_TPF_SCOREBOARD)
1235
1236 static void cleanup_scoreboard_heap()
1237 {
1238     int rv;
1239     rv = rsysc(ap_scoreboard_image, SCOREBOARD_FRAMES, SCOREBOARD_NAME);
1240     if(rv == RSYSC_ERROR) {
1241         ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1242             "rsysc() could not release scoreboard system heap");
1243     }
1244 }
1245
1246 static void setup_shared_mem(ap_context_t *p)
1247 {
1248     cinfc(CINFC_WRITE, CINFC_CMMCTK2);
1249     ap_scoreboard_image = (scoreboard *) gsysc(SCOREBOARD_FRAMES, SCOREBOARD_NAME);
1250
1251     if (!ap_scoreboard_image) {
1252         fprintf(stderr, "httpd: Could not create scoreboard system heap storage.\n");
1253         exit(APEXIT_INIT);
1254     }
1255
1256     ap_register_cleanup(p, NULL, cleanup_scoreboard_heap, ap_null_cleanup);
1257     ap_scoreboard_image->global.running_generation = 0;
1258 }
1259
1260 static void reopen_scoreboard(ap_context_t *p)
1261 {
1262     cinfc(CINFC_WRITE, CINFC_CMMCTK2);
1263 }
1264
1265 #else
1266 #define SCOREBOARD_FILE
1267 static scoreboard _scoreboard_image;
1268 static int scoreboard_fd = -1;
1269
1270 /* XXX: things are seriously screwed if we ever have to do a partial
1271  * read or write ... we could get a corrupted scoreboard
1272  */
1273 static int force_write(int fd, void *buffer, int bufsz)
1274 {
1275     int rv, orig_sz = bufsz;
1276
1277     do {
1278         rv = write(fd, buffer, bufsz);
1279         if (rv > 0) {
1280             buffer = (char *) buffer + rv;
1281             bufsz -= rv;
1282         }
1283     } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
1284
1285     return rv < 0 ? rv : orig_sz - bufsz;
1286 }
1287
1288 static int force_read(int fd, void *buffer, int bufsz)
1289 {
1290     int rv, orig_sz = bufsz;
1291
1292     do {
1293         rv = read(fd, buffer, bufsz);
1294         if (rv > 0) {
1295             buffer = (char *) buffer + rv;
1296             bufsz -= rv;
1297         }
1298     } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
1299
1300     return rv < 0 ? rv : orig_sz - bufsz;
1301 }
1302
1303 static void cleanup_scoreboard_file(void *foo)
1304 {
1305     unlink(ap_scoreboard_fname);
1306 }
1307
1308 void reopen_scoreboard(ap_context_t *p)
1309 {
1310     if (scoreboard_fd != -1)
1311         ap_pclosef(p, scoreboard_fd);
1312
1313 #ifdef TPF
1314     ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname);
1315 #endif /* TPF */
1316     scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | O_RDWR, 0666);
1317     if (scoreboard_fd == -1) {
1318         perror(ap_scoreboard_fname);
1319         fprintf(stderr, "Cannot open scoreboard file:\n");
1320         clean_child_exit(1);
1321     }
1322 }
1323 #endif
1324
1325 /* Called by parent process */
1326 static void reinit_scoreboard(ap_context_t *p)
1327 {
1328     int running_gen = 0;
1329     if (ap_scoreboard_image)
1330         running_gen = ap_scoreboard_image->global.running_generation;
1331
1332 #ifndef SCOREBOARD_FILE
1333     if (ap_scoreboard_image == NULL) {
1334         setup_shared_mem(p);
1335     }
1336     memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
1337     ap_scoreboard_image->global.running_generation = running_gen;
1338 #else
1339     ap_scoreboard_image = &_scoreboard_image;
1340     ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname);
1341
1342     scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | O_RDWR, 0644);
1343     if (scoreboard_fd == -1) {
1344         perror(ap_scoreboard_fname);
1345         fprintf(stderr, "Cannot open scoreboard file:\n");
1346         exit(APEXIT_INIT);
1347     }
1348     ap_register_cleanup(p, NULL, cleanup_scoreboard_file, ap_null_cleanup);
1349
1350     memset((char *) ap_scoreboard_image, 0, sizeof(*ap_scoreboard_image));
1351     ap_scoreboard_image->global.running_generation = running_gen;
1352     force_write(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image));
1353 #endif
1354 }
1355
1356 /* Routines called to deal with the scoreboard image
1357  * --- note that we do *not* need write locks, since update_child_status
1358  * only updates a *single* record in place, and only one process writes to
1359  * a given scoreboard slot at a time (either the child process owning that
1360  * slot, or the parent, noting that the child has died).
1361  *
1362  * As a final note --- setting the score entry to getpid() is always safe,
1363  * since when the parent is writing an entry, it's only noting SERVER_DEAD
1364  * anyway.
1365  */
1366
1367 ap_inline void ap_sync_scoreboard_image(void)
1368 {
1369 #ifdef SCOREBOARD_FILE
1370     lseek(scoreboard_fd, 0L, 0);
1371     force_read(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image));
1372 #endif
1373 }
1374
1375 API_EXPORT(int) ap_exists_scoreboard_image(void)
1376 {
1377     return (ap_scoreboard_image ? 1 : 0);
1378 }
1379
1380 static ap_inline void put_scoreboard_info(int child_num,
1381                                        short_score *new_score_rec)
1382 {
1383 #ifdef SCOREBOARD_FILE
1384     lseek(scoreboard_fd, (long) child_num * sizeof(short_score), 0);
1385     force_write(scoreboard_fd, new_score_rec, sizeof(short_score));
1386 #endif
1387 }
1388
1389 int ap_update_child_status(int child_num, int status, request_rec *r)
1390 {
1391     int old_status;
1392     short_score *ss;
1393
1394     if (child_num < 0)
1395         return -1;
1396
1397     ap_check_signals();
1398
1399     ap_sync_scoreboard_image();
1400     ss = &ap_scoreboard_image->servers[child_num];
1401     old_status = ss->status;
1402     ss->status = status;
1403
1404     if (ap_extended_status) {
1405         if (status == SERVER_READY || status == SERVER_DEAD) {
1406             /*
1407              * Reset individual counters
1408              */
1409             if (status == SERVER_DEAD) {
1410                 ss->my_access_count = 0L;
1411                 ss->my_bytes_served = 0L;
1412             }
1413             ss->conn_count = (unsigned short) 0;
1414             ss->conn_bytes = (unsigned long) 0;
1415         }
1416         if (r) {
1417             conn_rec *c = r->connection;
1418             ap_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config,
1419                                   REMOTE_NOLOOKUP), sizeof(ss->client));
1420             if (r->the_request == NULL) {
1421                     ap_cpystrn(ss->request, "NULL", sizeof(ss->request));
1422             } else if (r->parsed_uri.password == NULL) {
1423                     ap_cpystrn(ss->request, r->the_request, sizeof(ss->request));
1424             } else {
1425                 /* Don't reveal the password in the server-status view */
1426                     ap_cpystrn(ss->request, ap_pstrcat(r->pool, r->method, " ",
1427                                                ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD),
1428                                                r->assbackwards ? NULL : " ", r->protocol, NULL),
1429                                        sizeof(ss->request));
1430             }
1431             ss->vhostrec =  r->server;
1432         }
1433     }
1434     if (status == SERVER_STARTING && r == NULL) {
1435         /* clean up the slot's vhostrec pointer (maybe re-used)
1436          * and mark the slot as belonging to a new generation.
1437          */
1438         ss->vhostrec = NULL;
1439         ap_scoreboard_image->parent[child_num].generation = ap_my_generation;
1440 #ifdef SCOREBOARD_FILE
1441         lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[child_num]), 0);
1442         force_write(scoreboard_fd, &ap_scoreboard_image->parent[child_num],
1443             sizeof(parent_score));
1444 #endif
1445     }
1446     put_scoreboard_info(child_num, ss);
1447
1448     return old_status;
1449 }
1450
1451 static void update_scoreboard_global(void)
1452 {
1453 #ifdef SCOREBOARD_FILE
1454     lseek(scoreboard_fd,
1455           (char *) &ap_scoreboard_image->global -(char *) ap_scoreboard_image, 0);
1456     force_write(scoreboard_fd, &ap_scoreboard_image->global,
1457                 sizeof ap_scoreboard_image->global);
1458 #endif
1459 }
1460
1461 void ap_time_process_request(int child_num, int status)
1462 {
1463     short_score *ss;
1464 #if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES)
1465     struct tms tms_blk;
1466 #endif
1467
1468     if (child_num < 0)
1469         return;
1470
1471     ap_sync_scoreboard_image();
1472     ss = &ap_scoreboard_image->servers[child_num];
1473
1474     if (status == START_PREQUEST) {
1475 #if defined(NO_GETTIMEOFDAY)
1476 #ifndef NO_TIMES
1477         if ((ss->start_time = times(&tms_blk)) == -1)
1478 #endif /* NO_TIMES */
1479             ss->start_time = (clock_t) 0;
1480 #else
1481         if (gettimeofday(&ss->start_time, (struct timezone *) 0) < 0)
1482             ss->start_time.tv_sec =
1483                 ss->start_time.tv_usec = 0L;
1484 #endif
1485     }
1486     else if (status == STOP_PREQUEST) {
1487 #if defined(NO_GETTIMEOFDAY)
1488 #ifndef NO_TIMES
1489         if ((ss->stop_time = times(&tms_blk)) == -1)
1490 #endif
1491             ss->stop_time = ss->start_time = (clock_t) 0;
1492 #else
1493         if (gettimeofday(&ss->stop_time, (struct timezone *) 0) < 0)
1494             ss->stop_time.tv_sec =
1495                 ss->stop_time.tv_usec =
1496                 ss->start_time.tv_sec =
1497                 ss->start_time.tv_usec = 0L;
1498 #endif
1499
1500     }
1501
1502     put_scoreboard_info(child_num, ss);
1503 }
1504
1505 /*
1506 static void increment_counts(int child_num, request_rec *r)
1507 {
1508     long int bs = 0;
1509     short_score *ss;
1510
1511     ap_sync_scoreboard_image();
1512     ss = &ap_scoreboard_image->servers[child_num];
1513
1514     if (r->sent_bodyct)
1515         ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
1516
1517 #ifndef NO_TIMES
1518     times(&ss->times);
1519 #endif
1520     ss->access_count++;
1521     ss->my_access_count++;
1522     ss->conn_count++;
1523     ss->bytes_served += (unsigned long) bs;
1524     ss->my_bytes_served += (unsigned long) bs;
1525     ss->conn_bytes += (unsigned long) bs;
1526
1527     put_scoreboard_info(child_num, ss);
1528 }
1529 */
1530
1531 static int find_child_by_pid(int pid)
1532 {
1533     int i;
1534
1535     for (i = 0; i < max_daemons_limit; ++i)
1536         if (ap_scoreboard_image->parent[i].pid == pid)
1537             return i;
1538
1539     return -1;
1540 }
1541
1542 static void reclaim_child_processes(int terminate)
1543 {
1544 #ifndef MULTITHREAD
1545     int i, status;
1546     long int waittime = 1024 * 16;      /* in usecs */
1547     struct timeval tv;
1548     int waitret, tries;
1549     int not_dead_yet;
1550 #ifdef HAS_OTHER_CHILD
1551     other_child_rec *ocr, *nocr;
1552 #endif
1553
1554     ap_sync_scoreboard_image();
1555
1556     for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
1557         /* don't want to hold up progress any more than 
1558          * necessary, but we need to allow children a few moments to exit.
1559          * Set delay with an exponential backoff.
1560          */
1561         tv.tv_sec = waittime / 1000000;
1562         tv.tv_usec = waittime % 1000000;
1563         waittime = waittime * 4;
1564         ap_select(0, NULL, NULL, NULL, &tv);
1565
1566         /* now see who is done */
1567         not_dead_yet = 0;
1568         for (i = 0; i < max_daemons_limit; ++i) {
1569             int pid = ap_scoreboard_image->parent[i].pid;
1570
1571             if (pid == my_pid || pid == 0)
1572                 continue;
1573
1574             waitret = waitpid(pid, &status, WNOHANG);
1575             if (waitret == pid || waitret == -1) {
1576                 ap_scoreboard_image->parent[i].pid = 0;
1577                 continue;
1578             }
1579             ++not_dead_yet;
1580             switch (tries) {
1581             case 1:     /*  16ms */
1582             case 2:     /*  82ms */
1583                 break;
1584             case 3:     /* 344ms */
1585                 /* perhaps it missed the SIGHUP, lets try again */
1586                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
1587                             server_conf,
1588                     "child process %d did not exit, sending another SIGHUP",
1589                             pid);
1590                 kill(pid, SIGHUP);
1591                 waittime = 1024 * 16;
1592                 break;
1593             case 4:     /*  16ms */
1594             case 5:     /*  82ms */
1595             case 6:     /* 344ms */
1596                 break;
1597             case 7:     /* 1.4sec */
1598                 /* ok, now it's being annoying */
1599                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
1600                             server_conf,
1601                    "child process %d still did not exit, sending a SIGTERM",
1602                             pid);
1603                 kill(pid, SIGTERM);
1604                 break;
1605             case 8:     /*  6 sec */
1606                 /* die child scum */
1607                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
1608                    "child process %d still did not exit, sending a SIGKILL",
1609                             pid);
1610                 kill(pid, SIGKILL);
1611                 break;
1612             case 9:     /* 14 sec */
1613                 /* gave it our best shot, but alas...  If this really 
1614                  * is a child we are trying to kill and it really hasn't
1615                  * exited, we will likely fail to bind to the port
1616                  * after the restart.
1617                  */
1618                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
1619                             "could not make child process %d exit, "
1620                             "attempting to continue anyway", pid);
1621                 break;
1622             }
1623         }
1624 #ifdef HAS_OTHER_CHILD
1625         for (ocr = other_children; ocr; ocr = nocr) {
1626             nocr = ocr->next;
1627             if (ocr->pid == -1)
1628                 continue;
1629
1630             waitret = waitpid(ocr->pid, &status, WNOHANG);
1631             if (waitret == ocr->pid) {
1632                 ocr->pid = -1;
1633                 (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
1634             }
1635             else if (waitret == 0) {
1636                 (*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
1637                 ++not_dead_yet;
1638             }
1639             else if (waitret == -1) {
1640                 /* uh what the heck? they didn't call unregister? */
1641                 ocr->pid = -1;
1642                 (*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
1643             }
1644         }
1645 #endif
1646         if (!not_dead_yet) {
1647             /* nothing left to wait for */
1648             break;
1649         }
1650     }
1651 #endif /* ndef MULTITHREAD */
1652 }
1653
1654
1655 #if defined(NEED_WAITPID)
1656 /*
1657    Systems without a real waitpid sometimes lose a child's exit while waiting
1658    for another.  Search through the scoreboard for missing children.
1659  */
1660 int reap_children(ap_wait_t *status)
1661 {
1662     int n, pid;
1663
1664     for (n = 0; n < max_daemons_limit; ++n) {
1665         ap_sync_scoreboard_image();
1666         if (ap_scoreboard_image->servers[n].status != SERVER_DEAD &&
1667                 kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
1668             ap_update_child_status(n, SERVER_DEAD, NULL);
1669             /* just mark it as having a successful exit status */
1670             bzero((char *) status, sizeof(ap_wait_t));
1671             return(pid);
1672         }
1673     }
1674     return 0;
1675 }
1676 #endif
1677
1678 /* Finally, this routine is used by the caretaker process to wait for
1679  * a while...
1680  */
1681
1682 /* number of calls to wait_or_timeout between writable probes */
1683 #ifndef INTERVAL_OF_WRITABLE_PROBES
1684 #define INTERVAL_OF_WRITABLE_PROBES 10
1685 #endif
1686 static int wait_or_timeout_counter;
1687
1688 static int wait_or_timeout(ap_wait_t *status)
1689 {
1690     struct timeval tv;
1691     int ret;
1692
1693     ++wait_or_timeout_counter;
1694     if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
1695         wait_or_timeout_counter = 0;
1696 #ifdef HAS_OTHER_CHILD
1697         probe_writable_fds();
1698 #endif
1699     }
1700     ret = waitpid(-1, status, WNOHANG);
1701     if (ret == -1 && errno == EINTR) {
1702         return -1;
1703     }
1704     if (ret > 0) {
1705         return ret;
1706     }
1707 #ifdef NEED_WAITPID
1708     if ((ret = reap_children(status)) > 0) {
1709         return ret;
1710     }
1711 #endif
1712     tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
1713     tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
1714     ap_select(0, NULL, NULL, NULL, &tv);
1715     return -1;
1716 }
1717
1718 /* handle all varieties of core dumping signals */
1719 static void sig_coredump(int sig)
1720 {
1721     chdir(ap_coredump_dir);
1722     signal(sig, SIG_DFL);
1723     kill(getpid(), sig);
1724     /* At this point we've got sig blocked, because we're still inside
1725      * the signal handler.  When we leave the signal handler it will
1726      * be unblocked, and we'll take the signal... and coredump or whatever
1727      * is appropriate for this particular Unix.  In addition the parent
1728      * will see the real signal we received -- whereas if we called
1729      * abort() here, the parent would only see SIGABRT.
1730      */
1731 }
1732
1733 /*****************************************************************
1734  * Connection structures and accounting...
1735  */
1736
1737 static void just_die(int sig)
1738 {
1739     clean_child_exit(0);
1740 }
1741
1742 static int volatile deferred_die;
1743 static int volatile usr1_just_die;
1744
1745 static void usr1_handler(int sig)
1746 {
1747     if (usr1_just_die) {
1748         just_die(sig);
1749     }
1750     deferred_die = 1;
1751 }
1752
1753 /* volatile just in case */
1754 static int volatile shutdown_pending;
1755 static int volatile restart_pending;
1756 static int volatile is_graceful;
1757 ap_generation_t volatile ap_my_generation=0;
1758
1759 static void sig_term(int sig)
1760 {
1761     if (shutdown_pending == 1) {
1762         /* Um, is this _probably_ not an error, if the user has
1763          * tried to do a shutdown twice quickly, so we won't
1764          * worry about reporting it.
1765          */
1766         return;
1767     }
1768     shutdown_pending = 1;
1769 }
1770
1771 static void restart(int sig)
1772 {
1773     if (restart_pending == 1) {
1774         /* Probably not an error - don't bother reporting it */
1775         return;
1776     }
1777     restart_pending = 1;
1778     is_graceful = sig == SIGUSR1;
1779 }
1780
1781 static void set_signals(void)
1782 {
1783 #ifndef NO_USE_SIGACTION
1784     struct sigaction sa;
1785
1786     sigemptyset(&sa.sa_mask);
1787     sa.sa_flags = 0;
1788
1789     if (!one_process) {
1790         sa.sa_handler = sig_coredump;
1791 #if defined(SA_ONESHOT)
1792         sa.sa_flags = SA_ONESHOT;
1793 #elif defined(SA_RESETHAND)
1794         sa.sa_flags = SA_RESETHAND;
1795 #endif
1796         if (sigaction(SIGSEGV, &sa, NULL) < 0)
1797             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)");
1798 #ifdef SIGBUS
1799         if (sigaction(SIGBUS, &sa, NULL) < 0)
1800             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)");
1801 #endif
1802 #ifdef SIGABORT
1803         if (sigaction(SIGABORT, &sa, NULL) < 0)
1804             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)");
1805 #endif
1806 #ifdef SIGABRT
1807         if (sigaction(SIGABRT, &sa, NULL) < 0)
1808             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)");
1809 #endif
1810 #ifdef SIGILL
1811         if (sigaction(SIGILL, &sa, NULL) < 0)
1812             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGILL)");
1813 #endif
1814         sa.sa_flags = 0;
1815     }
1816     sa.sa_handler = sig_term;
1817     if (sigaction(SIGTERM, &sa, NULL) < 0)
1818         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)");
1819 #ifdef SIGINT
1820     if (sigaction(SIGINT, &sa, NULL) < 0)
1821         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)");
1822 #endif
1823 #ifdef SIGXCPU
1824     sa.sa_handler = SIG_DFL;
1825     if (sigaction(SIGXCPU, &sa, NULL) < 0)
1826         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)");
1827 #endif
1828 #ifdef SIGXFSZ
1829     sa.sa_handler = SIG_DFL;
1830     if (sigaction(SIGXFSZ, &sa, NULL) < 0)
1831         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
1832 #endif
1833 #ifdef SIGPIPE
1834     sa.sa_handler = SIG_IGN;
1835     if (sigaction(SIGPIPE, &sa, NULL) < 0)
1836         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)");
1837 #endif
1838
1839     /* we want to ignore HUPs and USR1 while we're busy processing one */
1840     sigaddset(&sa.sa_mask, SIGHUP);
1841     sigaddset(&sa.sa_mask, SIGUSR1);
1842     sa.sa_handler = restart;
1843     if (sigaction(SIGHUP, &sa, NULL) < 0)
1844         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)");
1845     if (sigaction(SIGUSR1, &sa, NULL) < 0)
1846         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGUSR1)");
1847 #else
1848     if (!one_process) {
1849         signal(SIGSEGV, sig_coredump);
1850 #ifdef SIGBUS
1851         signal(SIGBUS, sig_coredump);
1852 #endif /* SIGBUS */
1853 #ifdef SIGABORT
1854         signal(SIGABORT, sig_coredump);
1855 #endif /* SIGABORT */
1856 #ifdef SIGABRT
1857         signal(SIGABRT, sig_coredump);
1858 #endif /* SIGABRT */
1859 #ifdef SIGILL
1860         signal(SIGILL, sig_coredump);
1861 #endif /* SIGILL */
1862 #ifdef SIGXCPU
1863         signal(SIGXCPU, SIG_DFL);
1864 #endif /* SIGXCPU */
1865 #ifdef SIGXFSZ
1866         signal(SIGXFSZ, SIG_DFL);
1867 #endif /* SIGXFSZ */
1868     }
1869
1870     signal(SIGTERM, sig_term);
1871 #ifdef SIGHUP
1872     signal(SIGHUP, restart);
1873 #endif /* SIGHUP */
1874 #ifdef SIGUSR1
1875     signal(SIGUSR1, restart);
1876 #endif /* SIGUSR1 */
1877 #ifdef SIGPIPE
1878     signal(SIGPIPE, SIG_IGN);
1879 #endif /* SIGPIPE */
1880
1881 #endif
1882 }
1883
1884 #if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
1885 static void sock_disable_nagle(int s)
1886 {
1887     /* The Nagle algorithm says that we should delay sending partial
1888      * packets in hopes of getting more data.  We don't want to do
1889      * this; we are not telnet.  There are bad interactions between
1890      * persistent connections and Nagle's algorithm that have very severe
1891      * performance penalties.  (Failing to disable Nagle is not much of a
1892      * problem with simple HTTP.)
1893      *
1894      * In spite of these problems, failure here is not a shooting offense.
1895      */
1896     int just_say_no = 1;
1897
1898     if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
1899                    sizeof(int)) < 0) {
1900         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
1901                     "setsockopt: (TCP_NODELAY)");
1902     }
1903 }
1904
1905 #else
1906 #define sock_disable_nagle(s)   /* NOOP */
1907 #endif
1908
1909
1910 /*****************************************************************
1911  * Child process main loop.
1912  * The following vars are static to avoid getting clobbered by longjmp();
1913  * they are really private to child_main.
1914  */
1915
1916 static int srv;
1917 static ap_socket_t *csd;
1918 static int requests_this_child;
1919 static fd_set main_fds;
1920
1921 API_EXPORT(void) ap_child_terminate(request_rec *r)
1922 {
1923     r->connection->keepalive = 0;
1924     requests_this_child = ap_max_requests_per_child = 1;
1925 }
1926
1927 int ap_graceful_stop_signalled(void)
1928 {
1929     ap_sync_scoreboard_image();
1930     if (deferred_die ||
1931         ap_scoreboard_image->global.running_generation != ap_my_generation) {
1932         return 1;
1933     }
1934     return 0;
1935 }
1936
1937 static void child_main(int child_num_arg)
1938 {
1939     NET_SIZE_T clen;
1940     struct sockaddr sa_server;
1941     struct sockaddr sa_client;
1942     ap_listen_rec *lr;
1943     ap_listen_rec *last_lr;
1944     ap_listen_rec *first_lr;
1945     ap_context_t *ptrans;
1946     conn_rec *current_conn;
1947     ap_iol *iol;
1948     ap_status_t stat;
1949     int sockdes;
1950
1951     my_pid = getpid();
1952     csd = NULL;
1953     my_child_num = child_num_arg;
1954     requests_this_child = 0;
1955     last_lr = NULL;
1956
1957     /* Get a sub ap_context_t for global allocations in this child, so that
1958      * we can have cleanups occur when the child exits.
1959      */
1960     ap_create_context(&pchild, pconf);
1961
1962     ap_create_context(&ptrans, pchild);
1963
1964     /* needs to be done before we switch UIDs so we have permissions */
1965     reopen_scoreboard(pchild);
1966     SAFE_ACCEPT(accept_mutex_child_init(pchild));
1967
1968     if (unixd_setup_child()) {
1969         clean_child_exit(APEXIT_CHILDFATAL);
1970     }
1971
1972     ap_child_init_hook(pchild, server_conf);
1973
1974     (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
1975
1976     signal(SIGHUP, just_die);
1977     signal(SIGTERM, just_die);
1978
1979 #ifdef OS2
1980 /* Stop Ctrl-C/Ctrl-Break signals going to child processes */
1981     {
1982         unsigned long ulTimes;
1983         DosSetSignalExceptionFocus(0, &ulTimes);
1984     }
1985 #endif
1986
1987     while (!ap_graceful_stop_signalled()) {
1988         BUFF *conn_io;
1989
1990         /* Prepare to receive a SIGUSR1 due to graceful restart so that
1991          * we can exit cleanly.
1992          */
1993         usr1_just_die = 1;
1994         signal(SIGUSR1, usr1_handler);
1995
1996         /*
1997          * (Re)initialize this child to a pre-connection state.
1998          */
1999
2000         current_conn = NULL;
2001
2002         ap_clear_pool(ptrans);
2003
2004         if ((ap_max_requests_per_child > 0
2005              && requests_this_child++ >= ap_max_requests_per_child)) {
2006             clean_child_exit(0);
2007         }
2008
2009         (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
2010
2011         /*
2012          * Wait for an acceptable connection to arrive.
2013          */
2014
2015         /* Lock around "accept", if necessary */
2016         SAFE_ACCEPT(accept_mutex_on());
2017
2018         for (;;) {
2019             if (ap_listeners->next) {
2020                 /* more than one socket */
2021                 memcpy(&main_fds, &listenfds, sizeof(fd_set));
2022                 srv = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, NULL);
2023
2024                 if (srv < 0 && errno != EINTR) {
2025                     /* Single Unix documents select as returning errnos
2026                      * EBADF, EINTR, and EINVAL... and in none of those
2027                      * cases does it make sense to continue.  In fact
2028                      * on Linux 2.0.x we seem to end up with EFAULT
2029                      * occasionally, and we'd loop forever due to it.
2030                      */
2031                     ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "select: (listen)");
2032                     clean_child_exit(1);
2033                 }
2034
2035                 if (srv <= 0)
2036                     continue;
2037
2038                 /* we remember the last_lr we searched last time around so that
2039                    we don't end up starving any particular listening socket */
2040                 if (last_lr == NULL) {
2041                     lr = ap_listeners;
2042                 }
2043                 else {
2044                     lr = last_lr->next;
2045                     if (!lr)
2046                         lr = ap_listeners;
2047                 }
2048                 first_lr=lr;
2049                 do {
2050                     ap_get_os_sock(lr->sd, &sockdes);
2051                     if (FD_ISSET(sockdes, &main_fds))
2052                         goto got_listener;
2053                     lr = lr->next;
2054                     if (!lr)
2055                         lr = ap_listeners;
2056                 }
2057                 while (lr != first_lr);
2058                 /* FIXME: if we get here, something bad has happened, and we're
2059                    probably gonna spin forever.
2060                 */
2061                 continue;
2062         got_listener:
2063                 last_lr = lr;
2064                 sd = lr->sd;
2065             }
2066             else {
2067                 /* only one socket, just pretend we did the other stuff */
2068                 sd = ap_listeners->sd;
2069             }
2070
2071             /* if we accept() something we don't want to die, so we have to
2072              * defer the exit
2073              */
2074             usr1_just_die = 0;
2075             for (;;) {
2076                 if (deferred_die) {
2077                     /* we didn't get a socket, and we were told to die */
2078                     clean_child_exit(0);
2079                 }
2080                 clen = sizeof(sa_client);
2081                 stat = ap_accept(&csd, sd);
2082                 if (stat == APR_SUCCESS || stat != APR_EINTR)
2083                     break;
2084             }
2085
2086             if (stat == APR_SUCCESS)
2087                 break;          /* We have a socket ready for reading */
2088             else {
2089
2090 /* TODO: this accept result handling stuff should be abstracted...
2091  * it's already out of date between the various unix mpms
2092  */
2093                 /* Our old behaviour here was to continue after accept()
2094                  * errors.  But this leads us into lots of troubles
2095                  * because most of the errors are quite fatal.  For
2096                  * example, EMFILE can be caused by slow descriptor
2097                  * leaks (say in a 3rd party module, or libc).  It's
2098                  * foolish for us to continue after an EMFILE.  We also
2099                  * seem to tickle kernel bugs on some platforms which
2100                  * lead to never-ending loops here.  So it seems best
2101                  * to just exit in most cases.
2102                  */
2103                 switch (errno) {
2104 #ifdef EPROTO
2105                     /* EPROTO on certain older kernels really means
2106                      * ECONNABORTED, so we need to ignore it for them.
2107                      * See discussion in new-httpd archives nh.9701
2108                      * search for EPROTO.
2109                      *
2110                      * Also see nh.9603, search for EPROTO:
2111                      * There is potentially a bug in Solaris 2.x x<6,
2112                      * and other boxes that implement tcp sockets in
2113                      * userland (i.e. on top of STREAMS).  On these
2114                      * systems, EPROTO can actually result in a fatal
2115                      * loop.  See PR#981 for example.  It's hard to
2116                      * handle both uses of EPROTO.
2117                      */
2118                 case EPROTO:
2119 #endif
2120 #ifdef ECONNABORTED
2121                 case ECONNABORTED:
2122 #endif
2123                     /* Linux generates the rest of these, other tcp
2124                      * stacks (i.e. bsd) tend to hide them behind
2125                      * getsockopt() interfaces.  They occur when
2126                      * the net goes sour or the client disconnects
2127                      * after the three-way handshake has been done
2128                      * in the kernel but before userland has picked
2129                      * up the socket.
2130                      */
2131 #ifdef ECONNRESET
2132                 case ECONNRESET:
2133 #endif
2134 #ifdef ETIMEDOUT
2135                 case ETIMEDOUT:
2136 #endif
2137 #ifdef EHOSTUNREACH
2138                 case EHOSTUNREACH:
2139 #endif
2140 #ifdef ENETUNREACH
2141                 case ENETUNREACH:
2142 #endif
2143                     break;
2144 #ifdef ENETDOWN
2145                 case ENETDOWN:
2146                      /*
2147                       * When the network layer has been shut down, there
2148                       * is not much use in simply exiting: the parent
2149                       * would simply re-create us (and we'd fail again).
2150                       * Use the CHILDFATAL code to tear the server down.
2151                       * @@@ Martin's idea for possible improvement:
2152                       * A different approach would be to define
2153                       * a new APEXIT_NETDOWN exit code, the reception
2154                       * of which would make the parent shutdown all
2155                       * children, then idle-loop until it detected that
2156                       * the network is up again, and restart the children.
2157                       * Ben Hyde noted that temporary ENETDOWN situations
2158                       * occur in mobile IP.
2159                       */
2160                     ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
2161                         "accept: giving up.");
2162                     clean_child_exit(APEXIT_CHILDFATAL);
2163 #endif /*ENETDOWN*/
2164
2165 #ifdef TPF
2166                 case EINACT:
2167                     ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
2168                         "offload device inactive");
2169                     clean_child_exit(APEXIT_CHILDFATAL);
2170                     break;
2171                 default:
2172                     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
2173                         "select/accept error (%u)", errno);
2174                     clean_child_exit(APEXIT_CHILDFATAL);
2175 #else
2176                 default:
2177                     ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
2178                                 "accept: (client socket)");
2179                     clean_child_exit(1);
2180 #endif
2181                 }
2182             }
2183
2184             if (ap_graceful_stop_signalled()) {
2185                 clean_child_exit(0);
2186             }
2187             usr1_just_die = 1;
2188         }
2189
2190         SAFE_ACCEPT(accept_mutex_off());        /* unlock after "accept" */
2191
2192 #ifdef TPF
2193         if (csd == 0)                       /* 0 is invalid socket for TPF */
2194             continue;
2195 #endif
2196
2197         /* We've got a socket, let's at least process one request off the
2198          * socket before we accept a graceful restart request.  We set
2199          * the signal to ignore because we don't want to disturb any
2200          * third party code.
2201          */
2202         signal(SIGUSR1, SIG_IGN);
2203
2204         /*
2205          * We now have a connection, so set it up with the appropriate
2206          * socket options, file descriptors, and read/write buffers.
2207          */
2208
2209         ap_get_os_sock(csd, &sockdes);
2210
2211         clen = sizeof(sa_server);
2212         if (getsockname(sockdes, &sa_server, &clen) < 0) {
2213             ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
2214             ap_close_socket(csd);
2215             continue;
2216         }
2217
2218         sock_disable_nagle(sockdes);
2219
2220         iol = unix_attach_socket(sockdes);
2221         if (iol == NULL) {
2222             if (errno == EBADF) {
2223                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
2224                     "filedescriptor (%u) larger than FD_SETSIZE (%u) "
2225                     "found, you probably need to rebuild Apache with a "
2226                     "larger FD_SETSIZE", sockdes, FD_SETSIZE);
2227             }
2228             else {
2229                 ap_log_error(APLOG_MARK, APLOG_WARNING, NULL,
2230                     "error attaching to socket");
2231             }
2232             ap_close_socket(csd);
2233             continue;
2234         }
2235
2236         (void) ap_update_child_status(my_child_num, SERVER_BUSY_READ,
2237                                    (request_rec *) NULL);
2238
2239         conn_io = ap_bcreate(ptrans, B_RDWR);
2240
2241         ap_bpush_iol(conn_io, iol);
2242
2243         current_conn = ap_new_connection(ptrans, server_conf, conn_io,
2244                                          (struct sockaddr_in *) &sa_client,
2245                                          (struct sockaddr_in *) &sa_server,
2246                                          my_child_num);
2247
2248         ap_process_connection(current_conn);
2249     }
2250 }
2251
2252
2253 static int make_child(server_rec *s, int slot, time_t now)
2254 {
2255     int pid;
2256
2257     if (slot + 1 > max_daemons_limit) {
2258         max_daemons_limit = slot + 1;
2259     }
2260
2261     if (one_process) {
2262         signal(SIGHUP, just_die);
2263         signal(SIGINT, just_die);
2264 #ifdef SIGQUIT
2265         signal(SIGQUIT, SIG_DFL);
2266 #endif
2267         signal(SIGTERM, just_die);
2268         child_main(slot);
2269     }
2270
2271     (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL);
2272
2273
2274 #ifdef _OSD_POSIX
2275     /* BS2000 requires a "special" version of fork() before a setuid() call */
2276     if ((pid = os_fork(unixd_config.user_name)) == -1) {
2277 #elif defined(TPF)
2278     if ((pid = os_fork(s, slot)) == -1) {
2279 #else
2280     if ((pid = fork()) == -1) {
2281 #endif
2282         ap_log_error(APLOG_MARK, APLOG_ERR, s, "fork: Unable to fork new process");
2283
2284         /* fork didn't succeed. Fix the scoreboard or else
2285          * it will say SERVER_STARTING forever and ever
2286          */
2287         (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);
2288
2289         /* In case system resources are maxxed out, we don't want
2290            Apache running away with the CPU trying to fork over and
2291            over and over again. */
2292         sleep(10);
2293
2294         return -1;
2295     }
2296
2297     if (!pid) {
2298 #ifdef AIX_BIND_PROCESSOR
2299 /* by default AIX binds to a single processor
2300  * this bit unbinds children which will then bind to another cpu
2301  */
2302 #include <sys/processor.h>
2303         int status = bindprocessor(BINDPROCESS, (int)getpid(), 
2304                                    PROCESSOR_CLASS_ANY);
2305         if (status != OK) {
2306             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
2307                         "processor unbind failed %d", status);
2308         }
2309 #endif
2310         RAISE_SIGSTOP(MAKE_CHILD);
2311         /* Disable the restart signal handlers and enable the just_die stuff.
2312          * Note that since restart() just notes that a restart has been
2313          * requested there's no race condition here.
2314          */
2315         signal(SIGHUP, just_die);
2316         signal(SIGUSR1, just_die);
2317         signal(SIGTERM, just_die);
2318         child_main(slot);
2319     }
2320
2321     ap_scoreboard_image->parent[slot].pid = pid;
2322 #ifdef SCOREBOARD_FILE
2323     lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[slot]), 0);
2324     force_write(scoreboard_fd, &ap_scoreboard_image->parent[slot],
2325                 sizeof(parent_score));
2326 #endif
2327
2328     return 0;
2329 }
2330
2331
2332 /* start up a bunch of children */
2333 static void startup_children(int number_to_start)
2334 {
2335     int i;
2336     time_t now = time(0);
2337
2338     for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
2339         if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
2340             continue;
2341         }
2342         if (make_child(server_conf, i, now) < 0) {
2343             break;
2344         }
2345         --number_to_start;
2346     }
2347 }
2348
2349
2350 /*
2351  * idle_spawn_rate is the number of children that will be spawned on the
2352  * next maintenance cycle if there aren't enough idle servers.  It is
2353  * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
2354  * without the need to spawn.
2355  */
2356 static int idle_spawn_rate = 1;
2357 #ifndef MAX_SPAWN_RATE
2358 #define MAX_SPAWN_RATE  (32)
2359 #endif
2360 static int hold_off_on_exponential_spawning;
2361
2362 static void perform_idle_server_maintenance(void)
2363 {
2364     int i;
2365     int to_kill;
2366     int idle_count;
2367     short_score *ss;
2368     time_t now = time(0);
2369     int free_length;
2370     int free_slots[MAX_SPAWN_RATE];
2371     int last_non_dead;
2372     int total_non_dead;
2373
2374     /* initialize the free_list */
2375     free_length = 0;
2376
2377     to_kill = -1;
2378     idle_count = 0;
2379     last_non_dead = -1;
2380     total_non_dead = 0;
2381
2382     ap_sync_scoreboard_image();
2383     for (i = 0; i < ap_daemons_limit; ++i) {
2384         int status;
2385
2386         if (i >= max_daemons_limit && free_length == idle_spawn_rate)
2387             break;
2388         ss = &ap_scoreboard_image->servers[i];
2389         status = ss->status;
2390         if (status == SERVER_DEAD) {
2391             /* try to keep children numbers as low as possible */
2392             if (free_length < idle_spawn_rate) {
2393                 free_slots[free_length] = i;
2394                 ++free_length;
2395             }
2396         }
2397         else {
2398             /* We consider a starting server as idle because we started it
2399              * at least a cycle ago, and if it still hasn't finished starting
2400              * then we're just going to swamp things worse by forking more.
2401              * So we hopefully won't need to fork more if we count it.
2402              * This depends on the ordering of SERVER_READY and SERVER_STARTING.
2403              */
2404             if (status <= SERVER_READY) {
2405                 ++ idle_count;
2406                 /* always kill the highest numbered child if we have to...
2407                  * no really well thought out reason ... other than observing
2408                  * the server behaviour under linux where lower numbered children
2409                  * tend to service more hits (and hence are more likely to have
2410                  * their data in cpu caches).
2411                  */
2412                 to_kill = i;
2413             }
2414
2415             ++total_non_dead;
2416             last_non_dead = i;
2417         }
2418     }
2419     max_daemons_limit = last_non_dead + 1;
2420     if (idle_count > ap_daemons_max_free) {
2421         /* kill off one child... we use SIGUSR1 because that'll cause it to
2422          * shut down gracefully, in case it happened to pick up a request
2423          * while we were counting
2424          */
2425         kill(ap_scoreboard_image->parent[to_kill].pid, SIGUSR1);
2426         idle_spawn_rate = 1;
2427     }
2428     else if (idle_count < ap_daemons_min_free) {
2429         /* terminate the free list */
2430         if (free_length == 0) {
2431             /* only report this condition once */
2432             static int reported = 0;
2433
2434             if (!reported) {
2435                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
2436                             "server reached MaxClients setting, consider"
2437                             " raising the MaxClients setting");
2438                 reported = 1;
2439             }
2440             idle_spawn_rate = 1;
2441         }
2442         else {
2443             if (idle_spawn_rate >= 8) {
2444                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
2445                     "server seems busy, (you may need "
2446                     "to increase StartServers, or Min/MaxSpareServers), "
2447                     "spawning %d children, there are %d idle, and "
2448                     "%d total children", idle_spawn_rate,
2449                     idle_count, total_non_dead);
2450             }
2451             for (i = 0; i < free_length; ++i) {
2452 #ifdef TPF
2453         if(make_child(server_conf, free_slots[i], now) == -1) {
2454             if(free_length == 1) {
2455                 shutdown_pending = 1;
2456                 ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
2457                 "No active child processes: shutting down");
2458             }
2459         }
2460 #else
2461                 make_child(server_conf, free_slots[i], now);
2462 #endif /* TPF */
2463             }
2464             /* the next time around we want to spawn twice as many if this
2465              * wasn't good enough, but not if we've just done a graceful
2466              */
2467             if (hold_off_on_exponential_spawning) {
2468                 --hold_off_on_exponential_spawning;
2469             }
2470             else if (idle_spawn_rate < MAX_SPAWN_RATE) {
2471                 idle_spawn_rate *= 2;
2472             }
2473         }
2474     }
2475     else {
2476         idle_spawn_rate = 1;
2477     }
2478 }
2479
2480
2481 static void process_child_status(int pid, ap_wait_t status)
2482 {
2483     /* Child died... if it died due to a fatal error,
2484         * we should simply bail out.
2485         */
2486     if ((WIFEXITED(status)) &&
2487         WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
2488         ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, server_conf,
2489                         "Child %d returned a Fatal error... \n"
2490                         "Apache is exiting!",
2491                         pid);
2492         exit(APEXIT_CHILDFATAL);
2493     }
2494     if (WIFSIGNALED(status)) {
2495         switch (WTERMSIG(status)) {
2496         case SIGTERM:
2497         case SIGHUP:
2498         case SIGUSR1:
2499         case SIGKILL:
2500             break;
2501         default:
2502 #ifdef SYS_SIGLIST
2503 #ifdef WCOREDUMP
2504             if (WCOREDUMP(status)) {
2505                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
2506                              server_conf,
2507                              "child pid %d exit signal %s (%d), "
2508                              "possible coredump in %s",
2509                              pid, (WTERMSIG(status) >= NumSIG) ? "" : 
2510                              SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
2511                              ap_coredump_dir);
2512             }
2513             else {
2514 #endif
2515                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
2516                              server_conf,
2517                              "child pid %d exit signal %s (%d)", pid,
2518                              SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
2519 #ifdef WCOREDUMP
2520             }
2521 #endif
2522 #else
2523             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
2524                          server_conf,
2525                          "child pid %d exit signal %d",
2526                          pid, WTERMSIG(status));
2527 #endif
2528         }
2529     }
2530 }
2531
2532
2533 static int setup_listeners(ap_context_t *p, server_rec *s)
2534 {
2535     ap_listen_rec *lr;
2536     int sockdes;
2537
2538     if (ap_listen_open(p, s->port)) {
2539         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, s,
2540                     "no listening sockets available, shutting down");
2541         return -1;
2542     }
2543
2544     listenmaxfd = -1;
2545     FD_ZERO(&listenfds);
2546     for (lr = ap_listeners; lr; lr = lr->next) {
2547         ap_get_os_sock(lr->sd, &sockdes);
2548         FD_SET(sockdes, &listenfds);
2549         if (sockdes > listenmaxfd) {
2550             listenmaxfd = sockdes;
2551         }
2552     }
2553     return 0;
2554 }
2555
2556
2557 /*****************************************************************
2558  * Executive routines.
2559  */
2560
2561 int ap_mpm_run(ap_context_t *_pconf, ap_context_t *plog, server_rec *s)
2562 {
2563     int remaining_children_to_start;
2564
2565     pconf = _pconf;
2566
2567     server_conf = s;
2568  
2569     ap_log_pid(pconf, ap_pid_fname);
2570
2571     if (setup_listeners(pconf, s)) {
2572         /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
2573         return 1;
2574     }
2575
2576     SAFE_ACCEPT(accept_mutex_init(pconf));
2577     if (!is_graceful) {
2578         reinit_scoreboard(pconf);
2579     }
2580 #ifdef SCOREBOARD_FILE
2581     else {
2582         ap_scoreboard_fname = ap_server_root_relative(pconf, ap_scoreboard_fname);
2583         ap_note_cleanups_for_fd(pconf, scoreboard_fd);
2584     }
2585 #endif
2586
2587     set_signals();
2588
2589     if (ap_daemons_max_free < ap_daemons_min_free + 1)  /* Don't thrash... */
2590         ap_daemons_max_free = ap_daemons_min_free + 1;
2591
2592     /* If we're doing a graceful_restart then we're going to see a lot
2593         * of children exiting immediately when we get into the main loop
2594         * below (because we just sent them SIGUSR1).  This happens pretty
2595         * rapidly... and for each one that exits we'll start a new one until
2596         * we reach at least daemons_min_free.  But we may be permitted to
2597         * start more than that, so we'll just keep track of how many we're
2598         * supposed to start up without the 1 second penalty between each fork.
2599         */
2600     remaining_children_to_start = ap_daemons_to_start;
2601     if (remaining_children_to_start > ap_daemons_limit) {
2602         remaining_children_to_start = ap_daemons_limit;
2603     }
2604     if (!is_graceful) {
2605         startup_children(remaining_children_to_start);
2606         remaining_children_to_start = 0;
2607     }
2608     else {
2609         /* give the system some time to recover before kicking into
2610             * exponential mode */
2611         hold_off_on_exponential_spawning = 10;
2612     }
2613
2614     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2615                 "%s configured -- resuming normal operations",
2616                 ap_get_server_version());
2617     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
2618                 "Server built: %s", ap_get_server_built());
2619     restart_pending = shutdown_pending = 0;
2620
2621     while (!restart_pending && !shutdown_pending) {
2622         int child_slot;
2623         ap_wait_t status;
2624         int pid = wait_or_timeout(&status);
2625
2626         /* XXX: if it takes longer than 1 second for all our children
2627          * to start up and get into IDLE state then we may spawn an
2628          * extra child
2629          */
2630         if (pid >= 0) {
2631             process_child_status(pid, status);
2632             /* non-fatal death... note that it's gone in the scoreboard. */
2633             ap_sync_scoreboard_image();
2634             child_slot = find_child_by_pid(pid);
2635             if (child_slot >= 0) {
2636                 (void) ap_update_child_status(child_slot, SERVER_DEAD,
2637                                             (request_rec *) NULL);
2638                 if (remaining_children_to_start
2639                     && child_slot < ap_daemons_limit) {
2640                     /* we're still doing a 1-for-1 replacement of dead
2641                         * children with new children
2642                         */
2643                     make_child(server_conf, child_slot, time(0));
2644                     --remaining_children_to_start;
2645                 }
2646 #ifdef HAS_OTHER_CHILD
2647             }
2648             else if (reap_other_child(pid, status) == 0) {
2649                 /* handled */
2650 #endif
2651             }
2652             else if (is_graceful) {
2653                 /* Great, we've probably just lost a slot in the
2654                     * scoreboard.  Somehow we don't know about this
2655                     * child.
2656                     */
2657                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
2658                             "long lost child came home! (pid %d)", pid);
2659             }
2660             /* Don't perform idle maintenance when a child dies,
2661                 * only do it when there's a timeout.  Remember only a
2662                 * finite number of children can die, and it's pretty
2663                 * pathological for a lot to die suddenly.
2664                 */
2665             continue;
2666         }
2667         else if (remaining_children_to_start) {
2668             /* we hit a 1 second timeout in which none of the previous
2669                 * generation of children needed to be reaped... so assume
2670                 * they're all done, and pick up the slack if any is left.
2671                 */
2672             startup_children(remaining_children_to_start);
2673             remaining_children_to_start = 0;
2674             /* In any event we really shouldn't do the code below because
2675                 * few of the servers we just started are in the IDLE state
2676                 * yet, so we'd mistakenly create an extra server.
2677                 */
2678             continue;
2679         }
2680
2681         perform_idle_server_maintenance();
2682 #ifdef TPF
2683     shutdown_pending = os_check_server(tpf_server_name);
2684     ap_check_signals();
2685     sleep(1);
2686 #endif /*TPF */
2687     }
2688
2689     if (shutdown_pending) {
2690         /* Time to gracefully shut down:
2691          * Kill child processes, tell them to call child_exit, etc...
2692          */
2693         if (ap_killpg(getpgrp(), SIGTERM) < 0) {
2694             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
2695         }
2696         reclaim_child_processes(1);             /* Start with SIGTERM */
2697
2698         /* cleanup pid file on normal shutdown */
2699         {
2700             const char *pidfile = NULL;
2701             pidfile = ap_server_root_relative (pconf, ap_pid_fname);
2702             if ( pidfile != NULL && unlink(pidfile) == 0)
2703                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
2704                                 server_conf,
2705                                 "removed PID file %s (pid=%ld)",
2706                                 pidfile, (long)getpid());
2707         }
2708
2709         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2710                     "caught SIGTERM, shutting down");
2711         return 1;
2712     }
2713
2714     /* we've been told to restart */
2715     signal(SIGHUP, SIG_IGN);
2716     signal(SIGUSR1, SIG_IGN);
2717
2718     if (one_process) {
2719         /* not worth thinking about */
2720         return 1;
2721     }
2722
2723     /* advance to the next generation */
2724     /* XXX: we really need to make sure this new generation number isn't in
2725      * use by any of the children.
2726      */
2727     ++ap_my_generation;
2728     ap_scoreboard_image->global.running_generation = ap_my_generation;
2729     update_scoreboard_global();
2730
2731     if (is_graceful) {
2732 #ifndef SCOREBOARD_FILE
2733         int i;
2734 #endif
2735         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2736                     "SIGUSR1 received.  Doing graceful restart");
2737
2738         /* kill off the idle ones */
2739         if (ap_killpg(getpgrp(), SIGUSR1) < 0) {
2740             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGUSR1");
2741         }
2742 #ifndef SCOREBOARD_FILE
2743         /* This is mostly for debugging... so that we know what is still
2744             * gracefully dealing with existing request.  But we can't really
2745             * do it if we're in a SCOREBOARD_FILE because it'll cause
2746             * corruption too easily.
2747             */
2748         ap_sync_scoreboard_image();
2749         for (i = 0; i < ap_daemons_limit; ++i) {
2750             if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
2751                 ap_scoreboard_image->servers[i].status = SERVER_GRACEFUL;
2752             }
2753         }
2754 #endif
2755     }
2756     else {
2757         /* Kill 'em off */
2758         if (ap_killpg(getpgrp(), SIGHUP) < 0) {
2759             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGHUP");
2760         }
2761         reclaim_child_processes(0);             /* Not when just starting up */
2762         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2763                     "SIGHUP received.  Attempting to restart");
2764     }
2765
2766     if (!is_graceful) {
2767         ap_restart_time = time(NULL);
2768     }
2769
2770     return 0;
2771 }
2772
2773 static void prefork_pre_config(ap_context_t *p, ap_context_t *plog, ap_context_t *ptemp)
2774 {
2775     static int restart_num = 0;
2776
2777     one_process = !!getenv("ONE_PROCESS");
2778
2779     /* sigh, want this only the second time around */
2780     if (restart_num++ == 1) {
2781         is_graceful = 0;
2782
2783         if (!one_process) {
2784             unixd_detach();
2785         }
2786
2787         my_pid = getpid();
2788     }
2789
2790     unixd_pre_config();
2791     ap_listen_pre_config();
2792     ap_daemons_to_start = DEFAULT_START_DAEMON;
2793     ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON;
2794     ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON;
2795     ap_daemons_limit = HARD_SERVER_LIMIT;
2796     ap_pid_fname = DEFAULT_PIDLOG;
2797     ap_scoreboard_fname = DEFAULT_SCOREBOARD;
2798     ap_lock_fname = DEFAULT_LOCKFILE;
2799     ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
2800     ap_extended_status = 0;
2801
2802     ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
2803 }
2804
2805 static void prefork_hooks(void)
2806 {
2807     ap_hook_pre_config(prefork_pre_config,NULL,NULL,HOOK_MIDDLE);
2808     INIT_SIGLIST();
2809 #ifdef AUX3
2810     (void) set42sig();
2811 #endif
2812     /* TODO: set one_process properly */ one_process = 0;
2813 }
2814
2815 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) 
2816 {
2817     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2818     if (err != NULL) {
2819         return err;
2820     }
2821
2822     if (cmd->server->is_virtual) {
2823         return "PidFile directive not allowed in <VirtualHost>";
2824     }
2825     ap_pid_fname = arg;
2826     return NULL;
2827 }
2828
2829 static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg) 
2830 {
2831     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2832     if (err != NULL) {
2833         return err;
2834     }
2835
2836     ap_scoreboard_fname = arg;
2837     return NULL;
2838 }
2839
2840 static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg) 
2841 {
2842     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2843     if (err != NULL) {
2844         return err;
2845     }
2846
2847     ap_lock_fname = arg;
2848     return NULL;
2849 }
2850
2851 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg) 
2852 {
2853     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2854     if (err != NULL) {
2855         return err;
2856     }
2857
2858     ap_daemons_to_start = atoi(arg);
2859     return NULL;
2860 }
2861
2862 static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2863 {
2864     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2865     if (err != NULL) {
2866         return err;
2867     }
2868
2869     ap_daemons_min_free = atoi(arg);
2870     if (ap_daemons_min_free <= 0) {
2871        fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
2872        fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
2873        fprintf(stderr, "Please read the documentation.\n");
2874        ap_daemons_min_free = 1;
2875     }
2876        
2877     return NULL;
2878 }
2879
2880 static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2881 {
2882     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2883     if (err != NULL) {
2884         return err;
2885     }
2886
2887     ap_daemons_max_free = atoi(arg);
2888     return NULL;
2889 }
2890
2891 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) 
2892 {
2893     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2894     if (err != NULL) {
2895         return err;
2896     }
2897
2898     ap_daemons_limit = atoi(arg);
2899     if (ap_daemons_limit > HARD_SERVER_LIMIT) {
2900        fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
2901            "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
2902        fprintf(stderr, " lowering MaxClients to %d.  To increase, please "
2903            "see the\n", HARD_SERVER_LIMIT);
2904        fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
2905        ap_daemons_limit = HARD_SERVER_LIMIT;
2906     } 
2907     else if (ap_daemons_limit < 1) {
2908         fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
2909         ap_daemons_limit = 1;
2910     }
2911     return NULL;
2912 }
2913
2914 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) 
2915 {
2916     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2917     if (err != NULL) {
2918         return err;
2919     }
2920
2921     ap_max_requests_per_child = atoi(arg);
2922
2923     return NULL;
2924 }
2925
2926 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) 
2927 {
2928     struct stat finfo;
2929     const char *fname;
2930     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2931     if (err != NULL) {
2932         return err;
2933     }
2934
2935     fname = ap_server_root_relative(cmd->pool, arg);
2936     /* ZZZ change this to the AP func FileInfo*/
2937     if ((stat(fname, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
2938         return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, 
2939                           " does not exist or is not a directory", NULL);
2940     }
2941     ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
2942     return NULL;
2943 }
2944
2945 /* there are no threads in the prefork model, so the mutexes are
2946    nops. */
2947 /* TODO: make these #defines to eliminate the function call */
2948
2949 struct ap_thread_mutex {
2950     int dummy;
2951 };
2952
2953 API_EXPORT(ap_thread_mutex *) ap_thread_mutex_new(void)
2954 {
2955     return malloc(sizeof(ap_thread_mutex));
2956 }
2957
2958 API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
2959 {
2960 }
2961
2962 API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
2963 {
2964 }
2965
2966 API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
2967 {
2968     free(mtx);
2969 }
2970
2971
2972 static const command_rec prefork_cmds[] = {
2973 UNIX_DAEMON_COMMANDS
2974 LISTEN_COMMANDS
2975 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
2976     "A file for logging the server process ID"},
2977 { "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
2978     "A file for Apache to maintain runtime process management information"},
2979 { "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1,
2980     "The lockfile used when Apache needs to lock the accept() call"},
2981 { "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
2982   "Number of child processes launched at server startup" },
2983 { "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1,
2984   "Minimum number of idle children, to handle request spikes" },
2985 { "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
2986   "Maximum number of idle children" },
2987 { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
2988   "Maximum number of children alive at the same time" },
2989 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
2990   "Maximum number of requests a particular child serves before dying." },
2991 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
2992   "The location of the directory Apache changes to before dumping core" },
2993 { NULL }
2994 };
2995
2996 module MODULE_VAR_EXPORT mpm_prefork_module = {
2997     STANDARD20_MODULE_STUFF,
2998     NULL,                       /* create per-directory config structure */
2999     NULL,                       /* merge per-directory config structures */
3000     NULL,                       /* create per-server config structure */
3001     NULL,                       /* merge per-server config structures */
3002     prefork_cmds,               /* command ap_table_t */
3003     NULL,                       /* handlers */
3004     prefork_hooks,              /* register hooks */
3005 };