]> granicus.if.org Git - apache/blob - server/mpm/prefork/prefork.c
If last_lr is the last listener, then lr can start out NULL.
[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 "httpd.h"
91 #include "http_main.h"
92 #include "http_log.h"
93 #include "http_config.h"
94 #include "http_core.h"          /* for get_remote_host */
95 #include "http_connection.h"
96 #include "scoreboard_prefork.h"
97 #include "ap_mpm.h"
98 #include "unixd.h"
99 #include "iol_socket.h"
100 #include "ap_listen.h"
101 #ifdef USE_SHMGET_SCOREBOARD
102 #include <sys/types.h>
103 #include <sys/ipc.h>
104 #include <sys/shm.h>
105 #endif
106
107 #ifdef HAVE_BSTRING_H
108 #include <bstring.h>            /* for IRIX, FD_SET calls bzero() */
109 #endif
110
111 /* config globals */
112
113 static int ap_max_requests_per_child=0;
114 static char *ap_pid_fname=NULL;
115 static char *ap_scoreboard_fname=NULL;
116 static char *ap_lock_fname;
117 static char *ap_server_argv0=NULL;
118 static int ap_daemons_to_start=0;
119 static int ap_daemons_min_free=0;
120 static int ap_daemons_max_free=0;
121 static int ap_daemons_limit=0;
122 static time_t ap_restart_time=0;
123 static int ap_extended_status = 0;
124
125 /*
126  * The max child slot ever assigned, preserved across restarts.  Necessary
127  * to deal with MaxClients changes across SIGUSR1 restarts.  We use this
128  * value to optimize routines that have to scan the entire scoreboard.
129  */
130 static int max_daemons_limit = -1;
131
132 static char ap_coredump_dir[MAX_STRING_LEN];
133
134 /* *Non*-shared http_main globals... */
135
136 static server_rec *server_conf;
137 static int sd;
138 static fd_set listenfds;
139 static int listenmaxfd;
140
141 /* one_process --- debugging mode variable; can be set from the command line
142  * with the -X flag.  If set, this gets you the child_main loop running
143  * in the process which originally started up (no detach, no make_child),
144  * which is a pretty nice debugging environment.  (You'll get a SIGHUP
145  * early in standalone_main; just continue through.  This is the server
146  * trying to kill off any child processes which it might have lying
147  * around --- Apache doesn't keep track of their pids, it just sends
148  * SIGHUP to the process group, ignoring it in the root process.
149  * Continue through and you'll be fine.).
150  */
151
152 static int one_process = 0;
153
154 #ifdef HAS_OTHER_CHILD
155 /* used to maintain list of children which aren't part of the scoreboard */
156 typedef struct other_child_rec other_child_rec;
157 struct other_child_rec {
158     other_child_rec *next;
159     int pid;
160     void (*maintenance) (int, void *, ap_wait_t);
161     void *data;
162     int write_fd;
163 };
164 static other_child_rec *other_children;
165 #endif
166
167 static pool *pconf;             /* Pool for config stuff */
168 static pool *pchild;            /* Pool for httpd child stuff */
169
170 static int my_pid;      /* it seems silly to call getpid all the time */
171 #ifndef MULTITHREAD
172 static int my_child_num;
173 #endif
174
175 #ifdef TPF
176 int tpf_child = 0;
177 char tpf_server_name[INETD_SERVNAME_LENGTH+1];
178 #endif /* TPF */
179
180 static scoreboard *ap_scoreboard_image = NULL;
181
182 static int volatile exit_after_unblock = 0;
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(pool *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(pool *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(pool *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(pool *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(pool *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-initialize 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(pool *p)
531 {
532
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     lock_fd = ap_popenf(p, ap_lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0644);
546     if (lock_fd == -1) {
547         perror("open");
548         fprintf(stderr, "Cannot open lock file: %s\n", ap_lock_fname);
549         exit(APEXIT_INIT);
550     }
551     unlink(ap_lock_fname);
552 }
553
554 static void accept_mutex_on(void)
555 {
556     int ret;
557
558     while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR) {
559         /* nop */
560     }
561
562     if (ret < 0) {
563         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
564                     "fcntl: F_SETLKW: Error getting accept lock, exiting!  "
565                     "Perhaps you need to use the LockFile directive to place "
566                     "your lock file on a local disk!");
567         clean_child_exit(APEXIT_CHILDFATAL);
568     }
569 }
570
571 static void accept_mutex_off(void)
572 {
573     int ret;
574
575     while ((ret = fcntl(lock_fd, F_SETLKW, &unlock_it)) < 0 && errno == EINTR) {
576         /* nop */
577     }
578     if (ret < 0) {
579         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
580                     "fcntl: F_SETLKW: Error freeing accept lock, exiting!  "
581                     "Perhaps you need to use the LockFile directive to place "
582                     "your lock file on a local disk!");
583         clean_child_exit(APEXIT_CHILDFATAL);
584     }
585 }
586
587 #elif defined(USE_FLOCK_SERIALIZED_ACCEPT)
588
589 static int lock_fd = -1;
590
591 static void accept_mutex_cleanup(void *foo)
592 {
593     unlink(ap_lock_fname);
594 }
595
596 /*
597  * Initialize mutex lock.
598  * Done by each child at it's birth
599  */
600 static void accept_mutex_child_init(pool *p)
601 {
602
603     lock_fd = ap_popenf(p, ap_lock_fname, O_WRONLY, 0600);
604     if (lock_fd == -1) {
605         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
606                     "Child cannot open lock file: %s", ap_lock_fname);
607         clean_child_exit(APEXIT_CHILDINIT);
608     }
609 }
610
611 /*
612  * Initialize mutex lock.
613  * Must be safe to call this on a restart.
614  */
615 static void accept_mutex_init(pool *p)
616 {
617     expand_lock_fname(p);
618     unlink(ap_lock_fname);
619     lock_fd = ap_popenf(p, ap_lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0600);
620     if (lock_fd == -1) {
621         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
622                     "Parent cannot open lock file: %s", ap_lock_fname);
623         exit(APEXIT_INIT);
624     }
625     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
626 }
627
628 static void accept_mutex_on(void)
629 {
630     int ret;
631
632     while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR)
633         continue;
634
635     if (ret < 0) {
636         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
637                     "flock: LOCK_EX: Error getting accept lock. Exiting!");
638         clean_child_exit(APEXIT_CHILDFATAL);
639     }
640 }
641
642 static void accept_mutex_off(void)
643 {
644     if (flock(lock_fd, LOCK_UN) < 0) {
645         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
646                     "flock: LOCK_UN: Error freeing accept lock. Exiting!");
647         clean_child_exit(APEXIT_CHILDFATAL);
648     }
649 }
650
651 #elif defined(USE_OS2SEM_SERIALIZED_ACCEPT)
652
653 static HMTX lock_sem = -1;
654
655 static void accept_mutex_cleanup(void *foo)
656 {
657     DosReleaseMutexSem(lock_sem);
658     DosCloseMutexSem(lock_sem);
659 }
660
661 /*
662  * Initialize mutex lock.
663  * Done by each child at it's birth
664  */
665 static void accept_mutex_child_init(pool *p)
666 {
667     int rc = DosOpenMutexSem(NULL, &lock_sem);
668
669     if (rc != 0) {
670         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
671                     "Child cannot open lock semaphore, rc=%d", rc);
672         clean_child_exit(APEXIT_CHILDINIT);
673     }
674 }
675
676 /*
677  * Initialize mutex lock.
678  * Must be safe to call this on a restart.
679  */
680 static void accept_mutex_init(pool *p)
681 {
682     int rc = DosCreateMutexSem(NULL, &lock_sem, DC_SEM_SHARED, FALSE);
683
684     if (rc != 0) {
685         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
686                     "Parent cannot create lock semaphore, rc=%d", rc);
687         exit(APEXIT_INIT);
688     }
689
690     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
691 }
692
693 static void accept_mutex_on(void)
694 {
695     int rc = DosRequestMutexSem(lock_sem, SEM_INDEFINITE_WAIT);
696
697     if (rc != 0) {
698         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
699                     "OS2SEM: Error %d getting accept lock. Exiting!", rc);
700         clean_child_exit(APEXIT_CHILDFATAL);
701     }
702 }
703
704 static void accept_mutex_off(void)
705 {
706     int rc = DosReleaseMutexSem(lock_sem);
707     
708     if (rc != 0) {
709         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
710                     "OS2SEM: Error %d freeing accept lock. Exiting!", rc);
711         clean_child_exit(APEXIT_CHILDFATAL);
712     }
713 }
714
715 #elif defined(USE_TPF_CORE_SERIALIZED_ACCEPT)
716
717 static int tpf_core_held;
718
719 static void accept_mutex_cleanup(void *foo)
720 {
721     if(tpf_core_held)
722         coruc(RESOURCE_KEY);
723 }
724
725 #define accept_mutex_init(x)
726
727 static void accept_mutex_child_init(pool *p)
728 {
729     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
730     tpf_core_held = 0;
731 }
732
733 static void accept_mutex_on(void)
734 {
735     corhc(RESOURCE_KEY);
736     tpf_core_held = 1;
737     ap_check_signals();
738 }
739
740 static void accept_mutex_off(void)
741 {
742     coruc(RESOURCE_KEY);
743     tpf_core_held = 0;
744     ap_check_signals();
745 }
746
747 #else
748 /* Default --- no serialization.  Other methods *could* go here,
749  * as #elifs...
750  */
751 #if !defined(MULTITHREAD)
752 /* Multithreaded systems don't complete between processes for
753  * the sockets. */
754 #define NO_SERIALIZED_ACCEPT
755 #define accept_mutex_child_init(x)
756 #define accept_mutex_init(x)
757 #define accept_mutex_on()
758 #define accept_mutex_off()
759 #endif
760 #endif
761
762 /* On some architectures it's safe to do unserialized accept()s in the single
763  * Listen case.  But it's never safe to do it in the case where there's
764  * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
765  * when it's safe in the single Listen case.
766  */
767 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
768 #define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
769 #else
770 #define SAFE_ACCEPT(stmt) do {stmt;} while(0)
771 #endif
772
773
774 /*****************************************************************
775  * dealing with other children
776  */
777
778 #ifdef HAS_OTHER_CHILD
779 API_EXPORT(void) ap_register_other_child(int pid,
780                        void (*maintenance) (int reason, void *, ap_wait_t status),
781                           void *data, int write_fd)
782 {
783     other_child_rec *ocr;
784
785     ocr = ap_palloc(pconf, sizeof(*ocr));
786     ocr->pid = pid;
787     ocr->maintenance = maintenance;
788     ocr->data = data;
789     ocr->write_fd = write_fd;
790     ocr->next = other_children;
791     other_children = ocr;
792 }
793
794 /* note that since this can be called by a maintenance function while we're
795  * scanning the other_children list, all scanners should protect themself
796  * by loading ocr->next before calling any maintenance function.
797  */
798 API_EXPORT(void) ap_unregister_other_child(void *data)
799 {
800     other_child_rec **pocr, *nocr;
801
802     for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
803         if ((*pocr)->data == data) {
804             nocr = (*pocr)->next;
805             (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
806             *pocr = nocr;
807             /* XXX: um, well we've just wasted some space in pconf ? */
808             return;
809         }
810     }
811 }
812
813 /* test to ensure that the write_fds are all still writable, otherwise
814  * invoke the maintenance functions as appropriate */
815 static void probe_writable_fds(void)
816 {
817     fd_set writable_fds;
818     int fd_max;
819     other_child_rec *ocr, *nocr;
820     struct timeval tv;
821     int rc;
822
823     if (other_children == NULL)
824         return;
825
826     fd_max = 0;
827     FD_ZERO(&writable_fds);
828     do {
829         for (ocr = other_children; ocr; ocr = ocr->next) {
830             if (ocr->write_fd == -1)
831                 continue;
832             FD_SET(ocr->write_fd, &writable_fds);
833             if (ocr->write_fd > fd_max) {
834                 fd_max = ocr->write_fd;
835             }
836         }
837         if (fd_max == 0)
838             return;
839
840         tv.tv_sec = 0;
841         tv.tv_usec = 0;
842         rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
843     } while (rc == -1 && errno == EINTR);
844
845     if (rc == -1) {
846         /* XXX: uhh this could be really bad, we could have a bad file
847          * descriptor due to a bug in one of the maintenance routines */
848         ap_log_unixerr("probe_writable_fds", "select",
849                     "could not probe writable fds", server_conf);
850         return;
851     }
852     if (rc == 0)
853         return;
854
855     for (ocr = other_children; ocr; ocr = nocr) {
856         nocr = ocr->next;
857         if (ocr->write_fd == -1)
858             continue;
859         if (FD_ISSET(ocr->write_fd, &writable_fds))
860             continue;
861         (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
862     }
863 }
864
865 /* possibly reap an other_child, return 0 if yes, -1 if not */
866 static int reap_other_child(int pid, ap_wait_t status)
867 {
868     other_child_rec *ocr, *nocr;
869
870     for (ocr = other_children; ocr; ocr = nocr) {
871         nocr = ocr->next;
872         if (ocr->pid != pid)
873             continue;
874         ocr->pid = -1;
875         (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
876         return 0;
877     }
878     return -1;
879 }
880 #endif
881
882 /*****************************************************************
883  *
884  * Dealing with the scoreboard... a lot of these variables are global
885  * only to avoid getting clobbered by the longjmp() that happens when
886  * a hard timeout expires...
887  *
888  * We begin with routines which deal with the file itself... 
889  */
890
891 #if defined(USE_OS2_SCOREBOARD)
892
893 /* The next two routines are used to access shared memory under OS/2.  */
894 /* This requires EMX v09c to be installed.                           */
895
896 caddr_t create_shared_heap(const char *name, size_t size)
897 {
898     ULONG rc;
899     void *mem;
900     Heap_t h;
901
902     rc = DosAllocSharedMem(&mem, name, size,
903                            PAG_COMMIT | PAG_READ | PAG_WRITE);
904     if (rc != 0)
905         return NULL;
906     h = _ucreate(mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED,
907                  NULL, NULL);
908     if (h == NULL)
909         DosFreeMem(mem);
910     return (caddr_t) h;
911 }
912
913 caddr_t get_shared_heap(const char *Name)
914 {
915
916     PVOID BaseAddress;          /* Pointer to the base address of
917                                    the shared memory object */
918     ULONG AttributeFlags;       /* Flags describing characteristics
919                                    of the shared memory object */
920     APIRET rc;                  /* Return code */
921
922     /* Request read and write access to */
923     /*   the shared memory object       */
924     AttributeFlags = PAG_WRITE | PAG_READ;
925
926     rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags);
927
928     if (rc != 0) {
929         printf("DosGetNamedSharedMem error: return code = %ld", rc);
930         return 0;
931     }
932
933     return BaseAddress;
934 }
935
936 static void setup_shared_mem(pool *p)
937 {
938     caddr_t m;
939
940     int rc;
941
942     m = (caddr_t) create_shared_heap("\\SHAREMEM\\SCOREBOARD", SCOREBOARD_SIZE);
943     if (m == 0) {
944         fprintf(stderr, "%s: Could not create OS/2 Shared memory pool.\n",
945                 ap_server_argv0);
946         exit(APEXIT_INIT);
947     }
948
949     rc = _uopen((Heap_t) m);
950     if (rc != 0) {
951         fprintf(stderr,
952                 "%s: Could not uopen() newly created OS/2 Shared memory pool.\n",
953                 ap_server_argv0);
954     }
955     ap_scoreboard_image = (scoreboard *) m;
956     ap_scoreboard_image->global.running_generation = 0;
957 }
958
959 static void reopen_scoreboard(pool *p)
960 {
961     caddr_t m;
962     int rc;
963
964     m = (caddr_t) get_shared_heap("\\SHAREMEM\\SCOREBOARD");
965     if (m == 0) {
966         fprintf(stderr, "%s: Could not find existing OS/2 Shared memory pool.\n",
967                 ap_server_argv0);
968         exit(APEXIT_INIT);
969     }
970
971     rc = _uopen((Heap_t) m);
972     ap_scoreboard_image = (scoreboard *) m;
973 }
974
975 #elif defined(USE_POSIX_SCOREBOARD)
976 #include <sys/mman.h>
977 /* 
978  * POSIX 1003.4 style
979  *
980  * Note 1: 
981  * As of version 4.23A, shared memory in QNX must reside under /dev/shmem,
982  * where no subdirectories allowed.
983  *
984  * POSIX shm_open() and shm_unlink() will take care about this issue,
985  * but to avoid confusion, I suggest to redefine scoreboard file name
986  * in httpd.conf to cut "logs/" from it. With default setup actual name
987  * will be "/dev/shmem/logs.apache_status". 
988  * 
989  * If something went wrong and Apache did not unlinked this object upon
990  * exit, you can remove it manually, using "rm -f" command.
991  * 
992  * Note 2:
993  * <sys/mman.h> in QNX defines MAP_ANON, but current implementation 
994  * does NOT support BSD style anonymous mapping. So, the order of 
995  * conditional compilation is important: 
996  * this #ifdef section must be ABOVE the next one (BSD style).
997  *
998  * I tested this stuff and it works fine for me, but if it provides 
999  * trouble for you, just comment out USE_MMAP_SCOREBOARD in QNX section
1000  * of ap_config.h
1001  *
1002  * June 5, 1997, 
1003  * Igor N. Kovalenko -- infoh@mail.wplus.net
1004  */
1005
1006 static void cleanup_shared_mem(void *d)
1007 {
1008     shm_unlink(ap_scoreboard_fname);
1009 }
1010
1011 static void setup_shared_mem(pool *p)
1012 {
1013     char buf[512];
1014     caddr_t m;
1015     int fd;
1016
1017     fd = shm_open(ap_scoreboard_fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1018     if (fd == -1) {
1019         ap_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard",
1020                     ap_server_argv0);
1021         perror(buf);
1022         exit(APEXIT_INIT);
1023     }
1024     if (ltrunc(fd, (off_t) SCOREBOARD_SIZE, SEEK_SET) == -1) {
1025         ap_snprintf(buf, sizeof(buf), "%s: could not ltrunc scoreboard",
1026                     ap_server_argv0);
1027         perror(buf);
1028         shm_unlink(ap_scoreboard_fname);
1029         exit(APEXIT_INIT);
1030     }
1031     if ((m = (caddr_t) mmap((caddr_t) 0,
1032                             (size_t) SCOREBOARD_SIZE, PROT_READ | PROT_WRITE,
1033                             MAP_SHARED, fd, (off_t) 0)) == (caddr_t) - 1) {
1034         ap_snprintf(buf, sizeof(buf), "%s: cannot mmap scoreboard",
1035                     ap_server_argv0);
1036         perror(buf);
1037         shm_unlink(ap_scoreboard_fname);
1038         exit(APEXIT_INIT);
1039     }
1040     close(fd);
1041     ap_register_cleanup(p, NULL, cleanup_shared_mem, ap_null_cleanup);
1042     ap_scoreboard_image = (scoreboard *) m;
1043     ap_scoreboard_image->global.running_generation = 0;
1044 }
1045
1046 static void reopen_scoreboard(pool *p)
1047 {
1048 }
1049
1050 #elif defined(USE_MMAP_SCOREBOARD)
1051
1052 static void setup_shared_mem(pool *p)
1053 {
1054     caddr_t m;
1055
1056 #if defined(MAP_ANON)
1057 /* BSD style */
1058 #ifdef CONVEXOS11
1059     /*
1060      * 9-Aug-97 - Jeff Venters (venters@convex.hp.com)
1061      * ConvexOS maps address space as follows:
1062      *   0x00000000 - 0x7fffffff : Kernel
1063      *   0x80000000 - 0xffffffff : User
1064      * Start mmapped area 1GB above start of text.
1065      *
1066      * Also, the length requires a pointer as the actual length is
1067      * returned (rounded up to a page boundary).
1068      */
1069     {
1070         unsigned len = SCOREBOARD_SIZE;
1071
1072         m = mmap((caddr_t) 0xC0000000, &len,
1073                  PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, NOFD, 0);
1074     }
1075 #elif defined(MAP_TMPFILE)
1076     {
1077         char mfile[] = "/tmp/apache_shmem_XXXX";
1078         int fd = mkstemp(mfile);
1079         if (fd == -1) {
1080             perror("open");
1081             fprintf(stderr, "%s: Could not open %s\n", ap_server_argv0, mfile);
1082             exit(APEXIT_INIT);
1083         }
1084         m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
1085                 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1086         if (m == (caddr_t) - 1) {
1087             perror("mmap");
1088             fprintf(stderr, "%s: Could not mmap %s\n", ap_server_argv0, mfile);
1089             exit(APEXIT_INIT);
1090         }
1091         close(fd);
1092         unlink(mfile);
1093     }
1094 #else
1095     m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
1096              PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
1097 #endif
1098     if (m == (caddr_t) - 1) {
1099         perror("mmap");
1100         fprintf(stderr, "%s: Could not mmap memory\n", ap_server_argv0);
1101         exit(APEXIT_INIT);
1102     }
1103 #else
1104 /* Sun style */
1105     int fd;
1106
1107     fd = open("/dev/zero", O_RDWR);
1108     if (fd == -1) {
1109         perror("open");
1110         fprintf(stderr, "%s: Could not open /dev/zero\n", ap_server_argv0);
1111         exit(APEXIT_INIT);
1112     }
1113     m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
1114              PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1115     if (m == (caddr_t) - 1) {
1116         perror("mmap");
1117         fprintf(stderr, "%s: Could not mmap /dev/zero\n", ap_server_argv0);
1118         exit(APEXIT_INIT);
1119     }
1120     close(fd);
1121 #endif
1122     ap_scoreboard_image = (scoreboard *) m;
1123     ap_scoreboard_image->global.running_generation = 0;
1124 }
1125
1126 static void reopen_scoreboard(pool *p)
1127 {
1128 }
1129
1130 #elif defined(USE_SHMGET_SCOREBOARD)
1131 static key_t shmkey = IPC_PRIVATE;
1132 static int shmid = -1;
1133
1134 static void setup_shared_mem(pool *p)
1135 {
1136     struct shmid_ds shmbuf;
1137 #ifdef MOVEBREAK
1138     char *obrk;
1139 #endif
1140
1141     if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT | SHM_R | SHM_W)) == -1) {
1142 #ifdef LINUX
1143         if (errno == ENOSYS) {
1144             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
1145                          "Your kernel was built without CONFIG_SYSVIPC\n"
1146                          "%s: Please consult the Apache FAQ for details",
1147                          ap_server_argv0);
1148         }
1149 #endif
1150         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
1151                     "could not call shmget");
1152         exit(APEXIT_INIT);
1153     }
1154
1155     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
1156                 "created shared memory segment #%d", shmid);
1157
1158 #ifdef MOVEBREAK
1159     /*
1160      * Some SysV systems place the shared segment WAY too close
1161      * to the dynamic memory break point (sbrk(0)). This severely
1162      * limits the use of malloc/sbrk in the program since sbrk will
1163      * refuse to move past that point.
1164      *
1165      * To get around this, we move the break point "way up there",
1166      * attach the segment and then move break back down. Ugly
1167      */
1168     if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) {
1169         ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1170             "sbrk() could not move break");
1171     }
1172 #endif
1173
1174 #define BADSHMAT        ((scoreboard *)(-1))
1175     if ((ap_scoreboard_image = (scoreboard *) shmat(shmid, 0, 0)) == BADSHMAT) {
1176         ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, "shmat error");
1177         /*
1178          * We exit below, after we try to remove the segment
1179          */
1180     }
1181     else {                      /* only worry about permissions if we attached the segment */
1182         if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) {
1183             ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1184                 "shmctl() could not stat segment #%d", shmid);
1185         }
1186         else {
1187             shmbuf.shm_perm.uid = unixd_config.user_id;
1188             shmbuf.shm_perm.gid = unixd_config.group_id;
1189             if (shmctl(shmid, IPC_SET, &shmbuf) != 0) {
1190                 ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1191                     "shmctl() could not set segment #%d", shmid);
1192             }
1193         }
1194     }
1195     /*
1196      * We must avoid leaving segments in the kernel's
1197      * (small) tables.
1198      */
1199     if (shmctl(shmid, IPC_RMID, NULL) != 0) {
1200         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
1201                 "shmctl: IPC_RMID: could not remove shared memory segment #%d",
1202                 shmid);
1203     }
1204     if (ap_scoreboard_image == BADSHMAT)        /* now bailout */
1205         exit(APEXIT_INIT);
1206
1207 #ifdef MOVEBREAK
1208     if (obrk == (char *) -1)
1209         return;                 /* nothing else to do */
1210     if (sbrk(-(MOVEBREAK)) == (char *) -1) {
1211         ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1212             "sbrk() could not move break back");
1213     }
1214 #endif
1215     ap_scoreboard_image->global.running_generation = 0;
1216 }
1217
1218 static void reopen_scoreboard(pool *p)
1219 {
1220 }
1221
1222 #elif defined(USE_TPF_SCOREBOARD)
1223
1224 static void cleanup_scoreboard_heap()
1225 {
1226     int rv;
1227     rv = rsysc(ap_scoreboard_image, SCOREBOARD_FRAMES, SCOREBOARD_NAME);
1228     if(rv == RSYSC_ERROR) {
1229         ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
1230             "rsysc() could not release scoreboard system heap");
1231     }
1232 }
1233
1234 static void setup_shared_mem(pool *p)
1235 {
1236     cinfc(CINFC_WRITE, CINFC_CMMCTK2);
1237     ap_scoreboard_image = (scoreboard *) gsysc(SCOREBOARD_FRAMES, SCOREBOARD_NAME);
1238
1239     if (!ap_scoreboard_image) {
1240         fprintf(stderr, "httpd: Could not create scoreboard system heap storage.\n");
1241         exit(APEXIT_INIT);
1242     }
1243
1244     ap_register_cleanup(p, NULL, cleanup_scoreboard_heap, ap_null_cleanup);
1245     ap_scoreboard_image->global.running_generation = 0;
1246 }
1247
1248 static void reopen_scoreboard(pool *p)
1249 {
1250     cinfc(CINFC_WRITE, CINFC_CMMCTK2);
1251 }
1252
1253 #else
1254 #define SCOREBOARD_FILE
1255 static scoreboard _scoreboard_image;
1256 static int scoreboard_fd = -1;
1257
1258 /* XXX: things are seriously screwed if we ever have to do a partial
1259  * read or write ... we could get a corrupted scoreboard
1260  */
1261 static int force_write(int fd, void *buffer, int bufsz)
1262 {
1263     int rv, orig_sz = bufsz;
1264
1265     do {
1266         rv = write(fd, buffer, bufsz);
1267         if (rv > 0) {
1268             buffer = (char *) buffer + rv;
1269             bufsz -= rv;
1270         }
1271     } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
1272
1273     return rv < 0 ? rv : orig_sz - bufsz;
1274 }
1275
1276 static int force_read(int fd, void *buffer, int bufsz)
1277 {
1278     int rv, orig_sz = bufsz;
1279
1280     do {
1281         rv = read(fd, buffer, bufsz);
1282         if (rv > 0) {
1283             buffer = (char *) buffer + rv;
1284             bufsz -= rv;
1285         }
1286     } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
1287
1288     return rv < 0 ? rv : orig_sz - bufsz;
1289 }
1290
1291 static void cleanup_scoreboard_file(void *foo)
1292 {
1293     unlink(ap_scoreboard_fname);
1294 }
1295
1296 void reopen_scoreboard(pool *p)
1297 {
1298     if (scoreboard_fd != -1)
1299         ap_pclosef(p, scoreboard_fd);
1300
1301 #ifdef TPF
1302     ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname);
1303 #endif /* TPF */
1304     scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | O_RDWR, 0666);
1305     if (scoreboard_fd == -1) {
1306         perror(ap_scoreboard_fname);
1307         fprintf(stderr, "Cannot open scoreboard file:\n");
1308         clean_child_exit(1);
1309     }
1310 }
1311 #endif
1312
1313 /* Called by parent process */
1314 static void reinit_scoreboard(pool *p)
1315 {
1316     int running_gen = 0;
1317     if (ap_scoreboard_image)
1318         running_gen = ap_scoreboard_image->global.running_generation;
1319
1320 #ifndef SCOREBOARD_FILE
1321     if (ap_scoreboard_image == NULL) {
1322         setup_shared_mem(p);
1323     }
1324     memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
1325     ap_scoreboard_image->global.running_generation = running_gen;
1326 #else
1327     ap_scoreboard_image = &_scoreboard_image;
1328     ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname);
1329
1330     scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | O_RDWR, 0644);
1331     if (scoreboard_fd == -1) {
1332         perror(ap_scoreboard_fname);
1333         fprintf(stderr, "Cannot open scoreboard file:\n");
1334         exit(APEXIT_INIT);
1335     }
1336     ap_register_cleanup(p, NULL, cleanup_scoreboard_file, ap_null_cleanup);
1337
1338     memset((char *) ap_scoreboard_image, 0, sizeof(*ap_scoreboard_image));
1339     ap_scoreboard_image->global.running_generation = running_gen;
1340     force_write(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image));
1341 #endif
1342 }
1343
1344 /* Routines called to deal with the scoreboard image
1345  * --- note that we do *not* need write locks, since update_child_status
1346  * only updates a *single* record in place, and only one process writes to
1347  * a given scoreboard slot at a time (either the child process owning that
1348  * slot, or the parent, noting that the child has died).
1349  *
1350  * As a final note --- setting the score entry to getpid() is always safe,
1351  * since when the parent is writing an entry, it's only noting SERVER_DEAD
1352  * anyway.
1353  */
1354
1355 ap_inline void ap_sync_scoreboard_image(void)
1356 {
1357 #ifdef SCOREBOARD_FILE
1358     lseek(scoreboard_fd, 0L, 0);
1359     force_read(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image));
1360 #endif
1361 }
1362
1363 API_EXPORT(int) ap_exists_scoreboard_image(void)
1364 {
1365     return (ap_scoreboard_image ? 1 : 0);
1366 }
1367
1368 static ap_inline void put_scoreboard_info(int child_num,
1369                                        short_score *new_score_rec)
1370 {
1371 #ifdef SCOREBOARD_FILE
1372     lseek(scoreboard_fd, (long) child_num * sizeof(short_score), 0);
1373     force_write(scoreboard_fd, new_score_rec, sizeof(short_score));
1374 #endif
1375 }
1376
1377 int ap_update_child_status(int child_num, int status, request_rec *r)
1378 {
1379     int old_status;
1380     short_score *ss;
1381
1382     if (child_num < 0)
1383         return -1;
1384
1385     ap_check_signals();
1386
1387     ap_sync_scoreboard_image();
1388     ss = &ap_scoreboard_image->servers[child_num];
1389     old_status = ss->status;
1390     ss->status = status;
1391
1392     if (ap_extended_status) {
1393         if (status == SERVER_READY || status == SERVER_DEAD) {
1394             /*
1395              * Reset individual counters
1396              */
1397             if (status == SERVER_DEAD) {
1398                 ss->my_access_count = 0L;
1399                 ss->my_bytes_served = 0L;
1400             }
1401             ss->conn_count = (unsigned short) 0;
1402             ss->conn_bytes = (unsigned long) 0;
1403         }
1404         if (r) {
1405             conn_rec *c = r->connection;
1406             ap_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config,
1407                                   REMOTE_NOLOOKUP), sizeof(ss->client));
1408             if (r->the_request == NULL) {
1409                     ap_cpystrn(ss->request, "NULL", sizeof(ss->request));
1410             } else if (r->parsed_uri.password == NULL) {
1411                     ap_cpystrn(ss->request, r->the_request, sizeof(ss->request));
1412             } else {
1413                 /* Don't reveal the password in the server-status view */
1414                     ap_cpystrn(ss->request, ap_pstrcat(r->pool, r->method, " ",
1415                                                ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD),
1416                                                r->assbackwards ? NULL : " ", r->protocol, NULL),
1417                                        sizeof(ss->request));
1418             }
1419             ss->vhostrec =  r->server;
1420         }
1421     }
1422     if (status == SERVER_STARTING && r == NULL) {
1423         /* clean up the slot's vhostrec pointer (maybe re-used)
1424          * and mark the slot as belonging to a new generation.
1425          */
1426         ss->vhostrec = NULL;
1427         ap_scoreboard_image->parent[child_num].generation = ap_my_generation;
1428 #ifdef SCOREBOARD_FILE
1429         lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[child_num]), 0);
1430         force_write(scoreboard_fd, &ap_scoreboard_image->parent[child_num],
1431             sizeof(parent_score));
1432 #endif
1433     }
1434     put_scoreboard_info(child_num, ss);
1435
1436     return old_status;
1437 }
1438
1439 static void update_scoreboard_global(void)
1440 {
1441 #ifdef SCOREBOARD_FILE
1442     lseek(scoreboard_fd,
1443           (char *) &ap_scoreboard_image->global -(char *) ap_scoreboard_image, 0);
1444     force_write(scoreboard_fd, &ap_scoreboard_image->global,
1445                 sizeof ap_scoreboard_image->global);
1446 #endif
1447 }
1448
1449 void ap_time_process_request(int child_num, int status)
1450 {
1451     short_score *ss;
1452 #if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES)
1453     struct tms tms_blk;
1454 #endif
1455
1456     if (child_num < 0)
1457         return;
1458
1459     ap_sync_scoreboard_image();
1460     ss = &ap_scoreboard_image->servers[child_num];
1461
1462     if (status == START_PREQUEST) {
1463 #if defined(NO_GETTIMEOFDAY)
1464 #ifndef NO_TIMES
1465         if ((ss->start_time = times(&tms_blk)) == -1)
1466 #endif /* NO_TIMES */
1467             ss->start_time = (clock_t) 0;
1468 #else
1469         if (gettimeofday(&ss->start_time, (struct timezone *) 0) < 0)
1470             ss->start_time.tv_sec =
1471                 ss->start_time.tv_usec = 0L;
1472 #endif
1473     }
1474     else if (status == STOP_PREQUEST) {
1475 #if defined(NO_GETTIMEOFDAY)
1476 #ifndef NO_TIMES
1477         if ((ss->stop_time = times(&tms_blk)) == -1)
1478 #endif
1479             ss->stop_time = ss->start_time = (clock_t) 0;
1480 #else
1481         if (gettimeofday(&ss->stop_time, (struct timezone *) 0) < 0)
1482             ss->stop_time.tv_sec =
1483                 ss->stop_time.tv_usec =
1484                 ss->start_time.tv_sec =
1485                 ss->start_time.tv_usec = 0L;
1486 #endif
1487
1488     }
1489
1490     put_scoreboard_info(child_num, ss);
1491 }
1492
1493 static void increment_counts(int child_num, request_rec *r)
1494 {
1495     long int bs = 0;
1496     short_score *ss;
1497
1498     ap_sync_scoreboard_image();
1499     ss = &ap_scoreboard_image->servers[child_num];
1500
1501     if (r->sent_bodyct)
1502         ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
1503
1504 #ifndef NO_TIMES
1505     times(&ss->times);
1506 #endif
1507     ss->access_count++;
1508     ss->my_access_count++;
1509     ss->conn_count++;
1510     ss->bytes_served += (unsigned long) bs;
1511     ss->my_bytes_served += (unsigned long) bs;
1512     ss->conn_bytes += (unsigned long) bs;
1513
1514     put_scoreboard_info(child_num, ss);
1515 }
1516
1517 static int find_child_by_pid(int pid)
1518 {
1519     int i;
1520
1521     for (i = 0; i < max_daemons_limit; ++i)
1522         if (ap_scoreboard_image->parent[i].pid == pid)
1523             return i;
1524
1525     return -1;
1526 }
1527
1528 static void reclaim_child_processes(int terminate)
1529 {
1530 #ifndef MULTITHREAD
1531     int i, status;
1532     long int waittime = 1024 * 16;      /* in usecs */
1533     struct timeval tv;
1534     int waitret, tries;
1535     int not_dead_yet;
1536 #ifdef HAS_OTHER_CHILD
1537     other_child_rec *ocr, *nocr;
1538 #endif
1539
1540     ap_sync_scoreboard_image();
1541
1542     for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
1543         /* don't want to hold up progress any more than 
1544          * necessary, but we need to allow children a few moments to exit.
1545          * Set delay with an exponential backoff.
1546          */
1547         tv.tv_sec = waittime / 1000000;
1548         tv.tv_usec = waittime % 1000000;
1549         waittime = waittime * 4;
1550         ap_select(0, NULL, NULL, NULL, &tv);
1551
1552         /* now see who is done */
1553         not_dead_yet = 0;
1554         for (i = 0; i < max_daemons_limit; ++i) {
1555             int pid = ap_scoreboard_image->parent[i].pid;
1556
1557             if (pid == my_pid || pid == 0)
1558                 continue;
1559
1560             waitret = waitpid(pid, &status, WNOHANG);
1561             if (waitret == pid || waitret == -1) {
1562                 ap_scoreboard_image->parent[i].pid = 0;
1563                 continue;
1564             }
1565             ++not_dead_yet;
1566             switch (tries) {
1567             case 1:     /*  16ms */
1568             case 2:     /*  82ms */
1569                 break;
1570             case 3:     /* 344ms */
1571                 /* perhaps it missed the SIGHUP, lets try again */
1572                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
1573                             server_conf,
1574                     "child process %d did not exit, sending another SIGHUP",
1575                             pid);
1576                 kill(pid, SIGHUP);
1577                 waittime = 1024 * 16;
1578                 break;
1579             case 4:     /*  16ms */
1580             case 5:     /*  82ms */
1581             case 6:     /* 344ms */
1582                 break;
1583             case 7:     /* 1.4sec */
1584                 /* ok, now it's being annoying */
1585                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
1586                             server_conf,
1587                    "child process %d still did not exit, sending a SIGTERM",
1588                             pid);
1589                 kill(pid, SIGTERM);
1590                 break;
1591             case 8:     /*  6 sec */
1592                 /* die child scum */
1593                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
1594                    "child process %d still did not exit, sending a SIGKILL",
1595                             pid);
1596                 kill(pid, SIGKILL);
1597                 break;
1598             case 9:     /* 14 sec */
1599                 /* gave it our best shot, but alas...  If this really 
1600                  * is a child we are trying to kill and it really hasn't
1601                  * exited, we will likely fail to bind to the port
1602                  * after the restart.
1603                  */
1604                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
1605                             "could not make child process %d exit, "
1606                             "attempting to continue anyway", pid);
1607                 break;
1608             }
1609         }
1610 #ifdef HAS_OTHER_CHILD
1611         for (ocr = other_children; ocr; ocr = nocr) {
1612             nocr = ocr->next;
1613             if (ocr->pid == -1)
1614                 continue;
1615
1616             waitret = waitpid(ocr->pid, &status, WNOHANG);
1617             if (waitret == ocr->pid) {
1618                 ocr->pid = -1;
1619                 (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
1620             }
1621             else if (waitret == 0) {
1622                 (*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
1623                 ++not_dead_yet;
1624             }
1625             else if (waitret == -1) {
1626                 /* uh what the heck? they didn't call unregister? */
1627                 ocr->pid = -1;
1628                 (*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
1629             }
1630         }
1631 #endif
1632         if (!not_dead_yet) {
1633             /* nothing left to wait for */
1634             break;
1635         }
1636     }
1637 #endif /* ndef MULTITHREAD */
1638 }
1639
1640
1641 #if defined(NEED_WAITPID)
1642 /*
1643    Systems without a real waitpid sometimes lose a child's exit while waiting
1644    for another.  Search through the scoreboard for missing children.
1645  */
1646 int reap_children(ap_wait_t *status)
1647 {
1648     int n, pid;
1649
1650     for (n = 0; n < max_daemons_limit; ++n) {
1651         ap_sync_scoreboard_image();
1652         if (ap_scoreboard_image->servers[n].status != SERVER_DEAD &&
1653                 kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
1654             ap_update_child_status(n, SERVER_DEAD, NULL);
1655             /* just mark it as having a successful exit status */
1656             bzero((char *) status, sizeof(ap_wait_t));
1657             return(pid);
1658         }
1659     }
1660     return 0;
1661 }
1662 #endif
1663
1664 /* Finally, this routine is used by the caretaker process to wait for
1665  * a while...
1666  */
1667
1668 /* number of calls to wait_or_timeout between writable probes */
1669 #ifndef INTERVAL_OF_WRITABLE_PROBES
1670 #define INTERVAL_OF_WRITABLE_PROBES 10
1671 #endif
1672 static int wait_or_timeout_counter;
1673
1674 static int wait_or_timeout(ap_wait_t *status)
1675 {
1676     struct timeval tv;
1677     int ret;
1678
1679     ++wait_or_timeout_counter;
1680     if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
1681         wait_or_timeout_counter = 0;
1682 #ifdef HAS_OTHER_CHILD
1683         probe_writable_fds();
1684 #endif
1685     }
1686     ret = waitpid(-1, status, WNOHANG);
1687     if (ret == -1 && errno == EINTR) {
1688         return -1;
1689     }
1690     if (ret > 0) {
1691         return ret;
1692     }
1693 #ifdef NEED_WAITPID
1694     if ((ret = reap_children(status)) > 0) {
1695         return ret;
1696     }
1697 #endif
1698     tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
1699     tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
1700     ap_select(0, NULL, NULL, NULL, &tv);
1701     return -1;
1702 }
1703
1704
1705 #if defined(NSIG)
1706 #define NumSIG NSIG
1707 #elif defined(_NSIG)
1708 #define NumSIG _NSIG
1709 #elif defined(__NSIG)
1710 #define NumSIG __NSIG
1711 #else
1712 #define NumSIG 32   /* for 1998's unixes, this is still a good assumption */
1713 #endif
1714
1715 #ifdef SYS_SIGLIST /* platform has sys_siglist[] */
1716 #define INIT_SIGLIST()  /*nothing*/
1717 #else /* platform has no sys_siglist[], define our own */
1718 #define SYS_SIGLIST ap_sys_siglist
1719 #define INIT_SIGLIST() siglist_init();
1720
1721 const char *ap_sys_siglist[NumSIG];
1722
1723 static void siglist_init(void)
1724 {
1725     int sig;
1726
1727     ap_sys_siglist[0] = "Signal 0";
1728 #ifdef SIGHUP
1729     ap_sys_siglist[SIGHUP] = "Hangup";
1730 #endif
1731 #ifdef SIGINT
1732     ap_sys_siglist[SIGINT] = "Interrupt";
1733 #endif
1734 #ifdef SIGQUIT
1735     ap_sys_siglist[SIGQUIT] = "Quit";
1736 #endif
1737 #ifdef SIGILL
1738     ap_sys_siglist[SIGILL] = "Illegal instruction";
1739 #endif
1740 #ifdef SIGTRAP
1741     ap_sys_siglist[SIGTRAP] = "Trace/BPT trap";
1742 #endif
1743 #ifdef SIGIOT
1744     ap_sys_siglist[SIGIOT] = "IOT instruction";
1745 #endif
1746 #ifdef SIGABRT
1747     ap_sys_siglist[SIGABRT] = "Abort";
1748 #endif
1749 #ifdef SIGEMT
1750     ap_sys_siglist[SIGEMT] = "Emulator trap";
1751 #endif
1752 #ifdef SIGFPE
1753     ap_sys_siglist[SIGFPE] = "Arithmetic exception";
1754 #endif
1755 #ifdef SIGKILL
1756     ap_sys_siglist[SIGKILL] = "Killed";
1757 #endif
1758 #ifdef SIGBUS
1759     ap_sys_siglist[SIGBUS] = "Bus error";
1760 #endif
1761 #ifdef SIGSEGV
1762     ap_sys_siglist[SIGSEGV] = "Segmentation fault";
1763 #endif
1764 #ifdef SIGSYS
1765     ap_sys_siglist[SIGSYS] = "Bad system call";
1766 #endif
1767 #ifdef SIGPIPE
1768     ap_sys_siglist[SIGPIPE] = "Broken pipe";
1769 #endif
1770 #ifdef SIGALRM
1771     ap_sys_siglist[SIGALRM] = "Alarm clock";
1772 #endif
1773 #ifdef SIGTERM
1774     ap_sys_siglist[SIGTERM] = "Terminated";
1775 #endif
1776 #ifdef SIGUSR1
1777     ap_sys_siglist[SIGUSR1] = "User defined signal 1";
1778 #endif
1779 #ifdef SIGUSR2
1780     ap_sys_siglist[SIGUSR2] = "User defined signal 2";
1781 #endif
1782 #ifdef SIGCLD
1783     ap_sys_siglist[SIGCLD] = "Child status change";
1784 #endif
1785 #ifdef SIGCHLD
1786     ap_sys_siglist[SIGCHLD] = "Child status change";
1787 #endif
1788 #ifdef SIGPWR
1789     ap_sys_siglist[SIGPWR] = "Power-fail restart";
1790 #endif
1791 #ifdef SIGWINCH
1792     ap_sys_siglist[SIGWINCH] = "Window changed";
1793 #endif
1794 #ifdef SIGURG
1795     ap_sys_siglist[SIGURG] = "urgent socket condition";
1796 #endif
1797 #ifdef SIGPOLL
1798     ap_sys_siglist[SIGPOLL] = "Pollable event occurred";
1799 #endif
1800 #ifdef SIGIO
1801     ap_sys_siglist[SIGIO] = "socket I/O possible";
1802 #endif
1803 #ifdef SIGSTOP
1804     ap_sys_siglist[SIGSTOP] = "Stopped (signal)";
1805 #endif
1806 #ifdef SIGTSTP
1807     ap_sys_siglist[SIGTSTP] = "Stopped";
1808 #endif
1809 #ifdef SIGCONT
1810     ap_sys_siglist[SIGCONT] = "Continued";
1811 #endif
1812 #ifdef SIGTTIN
1813     ap_sys_siglist[SIGTTIN] = "Stopped (tty input)";
1814 #endif
1815 #ifdef SIGTTOU
1816     ap_sys_siglist[SIGTTOU] = "Stopped (tty output)";
1817 #endif
1818 #ifdef SIGVTALRM
1819     ap_sys_siglist[SIGVTALRM] = "virtual timer expired";
1820 #endif
1821 #ifdef SIGPROF
1822     ap_sys_siglist[SIGPROF] = "profiling timer expired";
1823 #endif
1824 #ifdef SIGXCPU
1825     ap_sys_siglist[SIGXCPU] = "exceeded cpu limit";
1826 #endif
1827 #ifdef SIGXFSZ
1828     ap_sys_siglist[SIGXFSZ] = "exceeded file size limit";
1829 #endif
1830     for (sig=0; sig < sizeof(ap_sys_siglist)/sizeof(ap_sys_siglist[0]); ++sig)
1831         if (ap_sys_siglist[sig] == NULL)
1832             ap_sys_siglist[sig] = "";
1833 }
1834 #endif /* platform has sys_siglist[] */
1835
1836
1837 /* handle all varieties of core dumping signals */
1838 static void sig_coredump(int sig)
1839 {
1840     chdir(ap_coredump_dir);
1841     signal(sig, SIG_DFL);
1842     kill(getpid(), sig);
1843     /* At this point we've got sig blocked, because we're still inside
1844      * the signal handler.  When we leave the signal handler it will
1845      * be unblocked, and we'll take the signal... and coredump or whatever
1846      * is appropriate for this particular Unix.  In addition the parent
1847      * will see the real signal we received -- whereas if we called
1848      * abort() here, the parent would only see SIGABRT.
1849      */
1850 }
1851
1852 /*****************************************************************
1853  * Connection structures and accounting...
1854  */
1855
1856 static void just_die(int sig)
1857 {
1858     clean_child_exit(0);
1859 }
1860
1861 static int volatile deferred_die;
1862 static int volatile usr1_just_die;
1863
1864 static void usr1_handler(int sig)
1865 {
1866     if (usr1_just_die) {
1867         just_die(sig);
1868     }
1869     deferred_die = 1;
1870 }
1871
1872 /* volatile just in case */
1873 static int volatile shutdown_pending;
1874 static int volatile restart_pending;
1875 static int volatile is_graceful;
1876 ap_generation_t volatile ap_my_generation=0;
1877
1878 static void sig_term(int sig)
1879 {
1880     if (shutdown_pending == 1) {
1881         /* Um, is this _probably_ not an error, if the user has
1882          * tried to do a shutdown twice quickly, so we won't
1883          * worry about reporting it.
1884          */
1885         return;
1886     }
1887     shutdown_pending = 1;
1888 }
1889
1890 static void restart(int sig)
1891 {
1892     if (restart_pending == 1) {
1893         /* Probably not an error - don't bother reporting it */
1894         return;
1895     }
1896     restart_pending = 1;
1897     is_graceful = sig == SIGUSR1;
1898 }
1899
1900 static void set_signals(void)
1901 {
1902 #ifndef NO_USE_SIGACTION
1903     struct sigaction sa;
1904
1905     sigemptyset(&sa.sa_mask);
1906     sa.sa_flags = 0;
1907
1908     if (!one_process) {
1909         sa.sa_handler = sig_coredump;
1910 #if defined(SA_ONESHOT)
1911         sa.sa_flags = SA_ONESHOT;
1912 #elif defined(SA_RESETHAND)
1913         sa.sa_flags = SA_RESETHAND;
1914 #endif
1915         if (sigaction(SIGSEGV, &sa, NULL) < 0)
1916             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)");
1917 #ifdef SIGBUS
1918         if (sigaction(SIGBUS, &sa, NULL) < 0)
1919             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)");
1920 #endif
1921 #ifdef SIGABORT
1922         if (sigaction(SIGABORT, &sa, NULL) < 0)
1923             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)");
1924 #endif
1925 #ifdef SIGABRT
1926         if (sigaction(SIGABRT, &sa, NULL) < 0)
1927             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)");
1928 #endif
1929 #ifdef SIGILL
1930         if (sigaction(SIGILL, &sa, NULL) < 0)
1931             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGILL)");
1932 #endif
1933         sa.sa_flags = 0;
1934     }
1935     sa.sa_handler = sig_term;
1936     if (sigaction(SIGTERM, &sa, NULL) < 0)
1937         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)");
1938 #ifdef SIGINT
1939     if (sigaction(SIGINT, &sa, NULL) < 0)
1940         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)");
1941 #endif
1942 #ifdef SIGXCPU
1943     sa.sa_handler = SIG_DFL;
1944     if (sigaction(SIGXCPU, &sa, NULL) < 0)
1945         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)");
1946 #endif
1947 #ifdef SIGXFSZ
1948     sa.sa_handler = SIG_DFL;
1949     if (sigaction(SIGXFSZ, &sa, NULL) < 0)
1950         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
1951 #endif
1952 #ifdef SIGPIPE
1953     sa.sa_handler = SIG_IGN;
1954     if (sigaction(SIGPIPE, &sa, NULL) < 0)
1955         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)");
1956 #endif
1957
1958     /* we want to ignore HUPs and USR1 while we're busy processing one */
1959     sigaddset(&sa.sa_mask, SIGHUP);
1960     sigaddset(&sa.sa_mask, SIGUSR1);
1961     sa.sa_handler = restart;
1962     if (sigaction(SIGHUP, &sa, NULL) < 0)
1963         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)");
1964     if (sigaction(SIGUSR1, &sa, NULL) < 0)
1965         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGUSR1)");
1966 #else
1967     if (!one_process) {
1968         signal(SIGSEGV, sig_coredump);
1969 #ifdef SIGBUS
1970         signal(SIGBUS, sig_coredump);
1971 #endif /* SIGBUS */
1972 #ifdef SIGABORT
1973         signal(SIGABORT, sig_coredump);
1974 #endif /* SIGABORT */
1975 #ifdef SIGABRT
1976         signal(SIGABRT, sig_coredump);
1977 #endif /* SIGABRT */
1978 #ifdef SIGILL
1979         signal(SIGILL, sig_coredump);
1980 #endif /* SIGILL */
1981 #ifdef SIGXCPU
1982         signal(SIGXCPU, SIG_DFL);
1983 #endif /* SIGXCPU */
1984 #ifdef SIGXFSZ
1985         signal(SIGXFSZ, SIG_DFL);
1986 #endif /* SIGXFSZ */
1987     }
1988
1989     signal(SIGTERM, sig_term);
1990 #ifdef SIGHUP
1991     signal(SIGHUP, restart);
1992 #endif /* SIGHUP */
1993 #ifdef SIGUSR1
1994     signal(SIGUSR1, restart);
1995 #endif /* SIGUSR1 */
1996 #ifdef SIGPIPE
1997     signal(SIGPIPE, SIG_IGN);
1998 #endif /* SIGPIPE */
1999
2000 #endif
2001 }
2002
2003 /*****************************************************************
2004  * Connection structures and accounting...
2005  */
2006
2007
2008 static conn_rec *new_connection(pool *p, server_rec *server, BUFF *inout,
2009                              const struct sockaddr_in *remaddr,
2010                              const struct sockaddr_in *saddr,
2011                              int child_num)
2012 {
2013     conn_rec *conn = (conn_rec *) ap_pcalloc(p, sizeof(conn_rec));
2014
2015     /* Got a connection structure, so initialize what fields we can
2016      * (the rest are zeroed out by pcalloc).
2017      */
2018
2019     conn->child_num = child_num;
2020
2021     conn->pool = p;
2022     conn->local_addr = *saddr;
2023     conn->base_server = server;
2024     conn->client = inout;
2025
2026     conn->remote_addr = *remaddr;
2027     conn->remote_ip = ap_pstrdup(conn->pool,
2028                               inet_ntoa(conn->remote_addr.sin_addr));
2029
2030     return conn;
2031 }
2032
2033 #if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
2034 static void sock_disable_nagle(int s)
2035 {
2036     /* The Nagle algorithm says that we should delay sending partial
2037      * packets in hopes of getting more data.  We don't want to do
2038      * this; we are not telnet.  There are bad interactions between
2039      * persistent connections and Nagle's algorithm that have very severe
2040      * performance penalties.  (Failing to disable Nagle is not much of a
2041      * problem with simple HTTP.)
2042      *
2043      * In spite of these problems, failure here is not a shooting offense.
2044      */
2045     int just_say_no = 1;
2046
2047     if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
2048                    sizeof(int)) < 0) {
2049         ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
2050                     "setsockopt: (TCP_NODELAY)");
2051     }
2052 }
2053
2054 #else
2055 #define sock_disable_nagle(s)   /* NOOP */
2056 #endif
2057
2058
2059 /*****************************************************************
2060  * Child process main loop.
2061  * The following vars are static to avoid getting clobbered by longjmp();
2062  * they are really private to child_main.
2063  */
2064
2065 static int srv;
2066 static int csd;
2067 static int requests_this_child;
2068 static fd_set main_fds;
2069
2070 API_EXPORT(void) ap_child_terminate(request_rec *r)
2071 {
2072     r->connection->keepalive = 0;
2073     requests_this_child = ap_max_requests_per_child = 1;
2074 }
2075
2076 int ap_graceful_stop_signalled(void)
2077 {
2078     ap_sync_scoreboard_image();
2079     if (deferred_die ||
2080         ap_scoreboard_image->global.running_generation != ap_my_generation) {
2081         return 1;
2082     }
2083     return 0;
2084 }
2085
2086 static void child_main(int child_num_arg)
2087 {
2088     NET_SIZE_T clen;
2089     struct sockaddr sa_server;
2090     struct sockaddr sa_client;
2091     ap_listen_rec *lr;
2092     ap_listen_rec *last_lr;
2093     pool *ptrans;
2094     conn_rec *current_conn;
2095     ap_iol *iol;
2096
2097     my_pid = getpid();
2098     csd = -1;
2099     my_child_num = child_num_arg;
2100     requests_this_child = 0;
2101     last_lr = NULL;
2102
2103     /* Get a sub pool for global allocations in this child, so that
2104      * we can have cleanups occur when the child exits.
2105      */
2106     pchild = ap_make_sub_pool(pconf);
2107
2108     ptrans = ap_make_sub_pool(pchild);
2109
2110     /* needs to be done before we switch UIDs so we have permissions */
2111     reopen_scoreboard(pchild);
2112     SAFE_ACCEPT(accept_mutex_child_init(pchild));
2113
2114     if (unixd_setup_child()) {
2115         clean_child_exit(APEXIT_CHILDFATAL);
2116     }
2117
2118     ap_child_init_hook(pchild, server_conf);
2119
2120     (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
2121
2122     signal(SIGHUP, just_die);
2123     signal(SIGTERM, just_die);
2124
2125 #ifdef OS2
2126 /* Stop Ctrl-C/Ctrl-Break signals going to child processes */
2127     {
2128         unsigned long ulTimes;
2129         DosSetSignalExceptionFocus(0, &ulTimes);
2130     }
2131 #endif
2132
2133     while (!ap_graceful_stop_signalled()) {
2134         BUFF *conn_io;
2135
2136         /* Prepare to receive a SIGUSR1 due to graceful restart so that
2137          * we can exit cleanly.
2138          */
2139         usr1_just_die = 1;
2140         signal(SIGUSR1, usr1_handler);
2141
2142         /*
2143          * (Re)initialize this child to a pre-connection state.
2144          */
2145
2146         current_conn = NULL;
2147
2148         ap_clear_pool(ptrans);
2149
2150         if ((ap_max_requests_per_child > 0
2151              && requests_this_child++ >= ap_max_requests_per_child)) {
2152             clean_child_exit(0);
2153         }
2154
2155         (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
2156
2157         /*
2158          * Wait for an acceptable connection to arrive.
2159          */
2160
2161         /* Lock around "accept", if necessary */
2162         SAFE_ACCEPT(accept_mutex_on());
2163
2164         for (;;) {
2165             if (ap_listeners->next) {
2166                 /* more than one socket */
2167                 memcpy(&main_fds, &listenfds, sizeof(fd_set));
2168                 srv = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, NULL);
2169
2170                 if (srv < 0 && errno != EINTR) {
2171                     /* Single Unix documents select as returning errnos
2172                      * EBADF, EINTR, and EINVAL... and in none of those
2173                      * cases does it make sense to continue.  In fact
2174                      * on Linux 2.0.x we seem to end up with EFAULT
2175                      * occasionally, and we'd loop forever due to it.
2176                      */
2177                     ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "select: (listen)");
2178                     clean_child_exit(1);
2179                 }
2180
2181                 if (srv <= 0)
2182                     continue;
2183
2184                 /* we remember the last_lr we searched last time around so that
2185                    we don't end up starving any particular listening socket */
2186                 if (last_lr == NULL) {
2187                     lr = ap_listeners;
2188                 }
2189                 else {
2190                     lr = last_lr->next;
2191                 }
2192                 while (lr != last_lr) {
2193                     if (!lr) {
2194                         lr = ap_listeners;
2195                     }
2196                     if (FD_ISSET(lr->fd, &main_fds)) break;
2197                     lr = lr->next;
2198                 }
2199                 if (lr == last_lr) {
2200                     continue;
2201                 }
2202                 last_lr = lr;
2203                 sd = lr->fd;
2204             }
2205             else {
2206                 /* only one socket, just pretend we did the other stuff */
2207                 sd = ap_listeners->fd;
2208             }
2209
2210             /* if we accept() something we don't want to die, so we have to
2211              * defer the exit
2212              */
2213             usr1_just_die = 0;
2214             for (;;) {
2215                 if (deferred_die) {
2216                     /* we didn't get a socket, and we were told to die */
2217                     clean_child_exit(0);
2218                 }
2219                 clen = sizeof(sa_client);
2220                 csd = ap_accept(sd, &sa_client, &clen);
2221                 if (csd >= 0 || errno != EINTR)
2222                     break;
2223             }
2224
2225             if (csd >= 0)
2226                 break;          /* We have a socket ready for reading */
2227             else {
2228
2229                 /* Our old behaviour here was to continue after accept()
2230                  * errors.  But this leads us into lots of troubles
2231                  * because most of the errors are quite fatal.  For
2232                  * example, EMFILE can be caused by slow descriptor
2233                  * leaks (say in a 3rd party module, or libc).  It's
2234                  * foolish for us to continue after an EMFILE.  We also
2235                  * seem to tickle kernel bugs on some platforms which
2236                  * lead to never-ending loops here.  So it seems best
2237                  * to just exit in most cases.
2238                  */
2239                 switch (errno) {
2240 #ifdef EPROTO
2241                     /* EPROTO on certain older kernels really means
2242                      * ECONNABORTED, so we need to ignore it for them.
2243                      * See discussion in new-httpd archives nh.9701
2244                      * search for EPROTO.
2245                      *
2246                      * Also see nh.9603, search for EPROTO:
2247                      * There is potentially a bug in Solaris 2.x x<6,
2248                      * and other boxes that implement tcp sockets in
2249                      * userland (i.e. on top of STREAMS).  On these
2250                      * systems, EPROTO can actually result in a fatal
2251                      * loop.  See PR#981 for example.  It's hard to
2252                      * handle both uses of EPROTO.
2253                      */
2254                 case EPROTO:
2255 #endif
2256 #ifdef ECONNABORTED
2257                 case ECONNABORTED:
2258 #endif
2259                     /* Linux generates the rest of these, other tcp
2260                      * stacks (i.e. bsd) tend to hide them behind
2261                      * getsockopt() interfaces.  They occur when
2262                      * the net goes sour or the client disconnects
2263                      * after the three-way handshake has been done
2264                      * in the kernel but before userland has picked
2265                      * up the socket.
2266                      */
2267 #ifdef ECONNRESET
2268                 case ECONNRESET:
2269 #endif
2270 #ifdef ETIMEDOUT
2271                 case ETIMEDOUT:
2272 #endif
2273 #ifdef EHOSTUNREACH
2274                 case EHOSTUNREACH:
2275 #endif
2276 #ifdef ENETUNREACH
2277                 case ENETUNREACH:
2278 #endif
2279                     break;
2280 #ifdef TPF
2281                 case EINACT:
2282                     ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
2283                         "offload device inactive");
2284                     clean_child_exit(APEXIT_CHILDFATAL);
2285                     break;
2286                 default:
2287                     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
2288                         "select/accept error (%u)", errno);
2289                     clean_child_exit(APEXIT_CHILDFATAL);
2290 #else
2291                 default:
2292                     ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
2293                                 "accept: (client socket)");
2294                     clean_child_exit(1);
2295 #endif
2296                 }
2297             }
2298
2299             if (ap_graceful_stop_signalled()) {
2300                 clean_child_exit(0);
2301             }
2302             usr1_just_die = 1;
2303         }
2304
2305         SAFE_ACCEPT(accept_mutex_off());        /* unlock after "accept" */
2306
2307 #ifdef TPF
2308         if (csd == 0)                       /* 0 is invalid socket for TPF */
2309             continue;
2310 #endif
2311
2312         /* We've got a socket, let's at least process one request off the
2313          * socket before we accept a graceful restart request.  We set
2314          * the signal to ignore because we don't want to disturb any
2315          * third party code.
2316          */
2317         signal(SIGUSR1, SIG_IGN);
2318
2319         /*
2320          * We now have a connection, so set it up with the appropriate
2321          * socket options, file descriptors, and read/write buffers.
2322          */
2323
2324         clen = sizeof(sa_server);
2325         if (getsockname(csd, &sa_server, &clen) < 0) {
2326             ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
2327             close(csd);
2328             continue;
2329         }
2330
2331         sock_disable_nagle(csd);
2332
2333         iol = unix_attach_socket(csd);
2334         if (iol == NULL) {
2335             if (errno == EBADF) {
2336                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
2337                     "filedescriptor (%u) larger than FD_SETSIZE (%u) "
2338                     "found, you probably need to rebuild Apache with a "
2339                     "larger FD_SETSIZE", csd, FD_SETSIZE);
2340             }
2341             else {
2342                 ap_log_error(APLOG_MARK, APLOG_WARNING, NULL,
2343                     "error attaching to socket");
2344             }
2345             close(csd);
2346             continue;
2347         }
2348
2349         (void) ap_update_child_status(my_child_num, SERVER_BUSY_READ,
2350                                    (request_rec *) NULL);
2351
2352         conn_io = ap_bcreate(ptrans, B_RDWR);
2353
2354         ap_bpush_iol(conn_io, iol);
2355
2356         current_conn = new_connection(ptrans, server_conf, conn_io,
2357                                           (struct sockaddr_in *) &sa_client,
2358                                           (struct sockaddr_in *) &sa_server,
2359                                           my_child_num);
2360
2361         ap_process_connection(current_conn);
2362     }
2363 }
2364
2365
2366 static int make_child(server_rec *s, int slot, time_t now)
2367 {
2368     int pid;
2369
2370     if (slot + 1 > max_daemons_limit) {
2371         max_daemons_limit = slot + 1;
2372     }
2373
2374     if (one_process) {
2375         signal(SIGHUP, just_die);
2376         signal(SIGINT, just_die);
2377 #ifdef SIGQUIT
2378         signal(SIGQUIT, SIG_DFL);
2379 #endif
2380         signal(SIGTERM, just_die);
2381         child_main(slot);
2382     }
2383
2384     (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL);
2385
2386
2387 #ifdef _OSD_POSIX
2388     /* BS2000 requires a "special" version of fork() before a setuid() call */
2389     if ((pid = os_fork(unixd_config.user_name)) == -1) {
2390 #elif defined(TPF)
2391     if ((pid = os_fork(s, slot)) == -1) {
2392 #else
2393     if ((pid = fork()) == -1) {
2394 #endif
2395         ap_log_error(APLOG_MARK, APLOG_ERR, s, "fork: Unable to fork new process");
2396
2397         /* fork didn't succeed. Fix the scoreboard or else
2398          * it will say SERVER_STARTING forever and ever
2399          */
2400         (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);
2401
2402         /* In case system resources are maxxed out, we don't want
2403            Apache running away with the CPU trying to fork over and
2404            over and over again. */
2405         sleep(10);
2406
2407         return -1;
2408     }
2409
2410     if (!pid) {
2411 #ifdef AIX_BIND_PROCESSOR
2412 /* by default AIX binds to a single processor
2413  * this bit unbinds children which will then bind to another cpu
2414  */
2415 #include <sys/processor.h>
2416         int status = bindprocessor(BINDPROCESS, (int)getpid(), 
2417                                    PROCESSOR_CLASS_ANY);
2418         if (status != OK) {
2419             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
2420                         "processor unbind failed %d", status);
2421         }
2422 #endif
2423         RAISE_SIGSTOP(MAKE_CHILD);
2424         /* Disable the restart signal handlers and enable the just_die stuff.
2425          * Note that since restart() just notes that a restart has been
2426          * requested there's no race condition here.
2427          */
2428         signal(SIGHUP, just_die);
2429         signal(SIGUSR1, just_die);
2430         signal(SIGTERM, just_die);
2431         child_main(slot);
2432     }
2433
2434     ap_scoreboard_image->parent[slot].pid = pid;
2435 #ifdef SCOREBOARD_FILE
2436     lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[slot]), 0);
2437     force_write(scoreboard_fd, &ap_scoreboard_image->parent[slot],
2438                 sizeof(parent_score));
2439 #endif
2440
2441     return 0;
2442 }
2443
2444
2445 /* start up a bunch of children */
2446 static void startup_children(int number_to_start)
2447 {
2448     int i;
2449     time_t now = time(0);
2450
2451     for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
2452         if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
2453             continue;
2454         }
2455         if (make_child(server_conf, i, now) < 0) {
2456             break;
2457         }
2458         --number_to_start;
2459     }
2460 }
2461
2462
2463 /*
2464  * idle_spawn_rate is the number of children that will be spawned on the
2465  * next maintenance cycle if there aren't enough idle servers.  It is
2466  * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
2467  * without the need to spawn.
2468  */
2469 static int idle_spawn_rate = 1;
2470 #ifndef MAX_SPAWN_RATE
2471 #define MAX_SPAWN_RATE  (32)
2472 #endif
2473 static int hold_off_on_exponential_spawning;
2474
2475 static void perform_idle_server_maintenance(void)
2476 {
2477     int i;
2478     int to_kill;
2479     int idle_count;
2480     short_score *ss;
2481     time_t now = time(0);
2482     int free_length;
2483     int free_slots[MAX_SPAWN_RATE];
2484     int last_non_dead;
2485     int total_non_dead;
2486
2487     /* initialize the free_list */
2488     free_length = 0;
2489
2490     to_kill = -1;
2491     idle_count = 0;
2492     last_non_dead = -1;
2493     total_non_dead = 0;
2494
2495     ap_sync_scoreboard_image();
2496     for (i = 0; i < ap_daemons_limit; ++i) {
2497         int status;
2498
2499         if (i >= max_daemons_limit && free_length == idle_spawn_rate)
2500             break;
2501         ss = &ap_scoreboard_image->servers[i];
2502         status = ss->status;
2503         if (status == SERVER_DEAD) {
2504             /* try to keep children numbers as low as possible */
2505             if (free_length < idle_spawn_rate) {
2506                 free_slots[free_length] = i;
2507                 ++free_length;
2508             }
2509         }
2510         else {
2511             /* We consider a starting server as idle because we started it
2512              * at least a cycle ago, and if it still hasn't finished starting
2513              * then we're just going to swamp things worse by forking more.
2514              * So we hopefully won't need to fork more if we count it.
2515              * This depends on the ordering of SERVER_READY and SERVER_STARTING.
2516              */
2517             if (status <= SERVER_READY) {
2518                 ++ idle_count;
2519                 /* always kill the highest numbered child if we have to...
2520                  * no really well thought out reason ... other than observing
2521                  * the server behaviour under linux where lower numbered children
2522                  * tend to service more hits (and hence are more likely to have
2523                  * their data in cpu caches).
2524                  */
2525                 to_kill = i;
2526             }
2527
2528             ++total_non_dead;
2529             last_non_dead = i;
2530         }
2531     }
2532     max_daemons_limit = last_non_dead + 1;
2533     if (idle_count > ap_daemons_max_free) {
2534         /* kill off one child... we use SIGUSR1 because that'll cause it to
2535          * shut down gracefully, in case it happened to pick up a request
2536          * while we were counting
2537          */
2538         kill(ap_scoreboard_image->parent[to_kill].pid, SIGUSR1);
2539         idle_spawn_rate = 1;
2540     }
2541     else if (idle_count < ap_daemons_min_free) {
2542         /* terminate the free list */
2543         if (free_length == 0) {
2544             /* only report this condition once */
2545             static int reported = 0;
2546
2547             if (!reported) {
2548                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
2549                             "server reached MaxClients setting, consider"
2550                             " raising the MaxClients setting");
2551                 reported = 1;
2552             }
2553             idle_spawn_rate = 1;
2554         }
2555         else {
2556             if (idle_spawn_rate >= 8) {
2557                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
2558                     "server seems busy, (you may need "
2559                     "to increase StartServers, or Min/MaxSpareServers), "
2560                     "spawning %d children, there are %d idle, and "
2561                     "%d total children", idle_spawn_rate,
2562                     idle_count, total_non_dead);
2563             }
2564             for (i = 0; i < free_length; ++i) {
2565 #ifdef TPF
2566         if(make_child(server_conf, free_slots[i], now) == -1) {
2567             if(free_length == 1) {
2568                 shutdown_pending = 1;
2569                 ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
2570                 "No active child processes: shutting down");
2571             }
2572         }
2573 #else
2574                 make_child(server_conf, free_slots[i], now);
2575 #endif /* TPF */
2576             }
2577             /* the next time around we want to spawn twice as many if this
2578              * wasn't good enough, but not if we've just done a graceful
2579              */
2580             if (hold_off_on_exponential_spawning) {
2581                 --hold_off_on_exponential_spawning;
2582             }
2583             else if (idle_spawn_rate < MAX_SPAWN_RATE) {
2584                 idle_spawn_rate *= 2;
2585             }
2586         }
2587     }
2588     else {
2589         idle_spawn_rate = 1;
2590     }
2591 }
2592
2593
2594 static void process_child_status(int pid, ap_wait_t status)
2595 {
2596     /* Child died... if it died due to a fatal error,
2597         * we should simply bail out.
2598         */
2599     if ((WIFEXITED(status)) &&
2600         WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
2601         ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, server_conf,
2602                         "Child %d returned a Fatal error... \n"
2603                         "Apache is exiting!",
2604                         pid);
2605         exit(APEXIT_CHILDFATAL);
2606     }
2607     if (WIFSIGNALED(status)) {
2608         switch (WTERMSIG(status)) {
2609         case SIGTERM:
2610         case SIGHUP:
2611         case SIGUSR1:
2612         case SIGKILL:
2613             break;
2614         default:
2615 #ifdef SYS_SIGLIST
2616 #ifdef WCOREDUMP
2617             if (WCOREDUMP(status)) {
2618                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
2619                              server_conf,
2620                              "child pid %d exit signal %s (%d), "
2621                              "possible coredump in %s",
2622                              pid, (WTERMSIG(status) >= NumSIG) ? "" : 
2623                              SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
2624                              ap_coredump_dir);
2625             }
2626             else {
2627 #endif
2628                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
2629                              server_conf,
2630                              "child pid %d exit signal %s (%d)", pid,
2631                              SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
2632 #ifdef WCOREDUMP
2633             }
2634 #endif
2635 #else
2636             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
2637                          server_conf,
2638                          "child pid %d exit signal %d",
2639                          pid, WTERMSIG(status));
2640 #endif
2641         }
2642     }
2643 }
2644
2645
2646 static int setup_listeners(pool *pconf, server_rec *s)
2647 {
2648     ap_listen_rec *lr;
2649
2650     if (ap_listen_open(pconf, s->port)) {
2651         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, s,
2652                     "no listening sockets available, shutting down");
2653         return -1;
2654     }
2655
2656     listenmaxfd = -1;
2657     FD_ZERO(&listenfds);
2658     for (lr = ap_listeners; lr; lr = lr->next) {
2659         FD_SET(lr->fd, &listenfds);
2660         if (lr->fd > listenmaxfd) {
2661             listenmaxfd = lr->fd;
2662         }
2663     }
2664     return 0;
2665 }
2666
2667
2668 /*****************************************************************
2669  * Executive routines.
2670  */
2671
2672 int ap_mpm_run(pool *_pconf, pool *plog, server_rec *s)
2673 {
2674     int remaining_children_to_start;
2675
2676     pconf = _pconf;
2677
2678     server_conf = s;
2679
2680     ap_log_pid(pconf, ap_pid_fname);
2681
2682     if (setup_listeners(pconf, s)) {
2683         /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
2684         return 1;
2685     }
2686
2687     SAFE_ACCEPT(accept_mutex_init(pconf));
2688     if (!is_graceful) {
2689         reinit_scoreboard(pconf);
2690     }
2691 #ifdef SCOREBOARD_FILE
2692     else {
2693         ap_scoreboard_fname = ap_server_root_relative(pconf, ap_scoreboard_fname);
2694         ap_note_cleanups_for_fd(pconf, scoreboard_fd);
2695     }
2696 #endif
2697
2698     set_signals();
2699
2700     if (ap_daemons_max_free < ap_daemons_min_free + 1)  /* Don't thrash... */
2701         ap_daemons_max_free = ap_daemons_min_free + 1;
2702
2703     /* If we're doing a graceful_restart then we're going to see a lot
2704         * of children exiting immediately when we get into the main loop
2705         * below (because we just sent them SIGUSR1).  This happens pretty
2706         * rapidly... and for each one that exits we'll start a new one until
2707         * we reach at least daemons_min_free.  But we may be permitted to
2708         * start more than that, so we'll just keep track of how many we're
2709         * supposed to start up without the 1 second penalty between each fork.
2710         */
2711     remaining_children_to_start = ap_daemons_to_start;
2712     if (remaining_children_to_start > ap_daemons_limit) {
2713         remaining_children_to_start = ap_daemons_limit;
2714     }
2715     if (!is_graceful) {
2716         startup_children(remaining_children_to_start);
2717         remaining_children_to_start = 0;
2718     }
2719     else {
2720         /* give the system some time to recover before kicking into
2721             * exponential mode */
2722         hold_off_on_exponential_spawning = 10;
2723     }
2724
2725     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2726                 "%s configured -- resuming normal operations",
2727                 ap_get_server_version());
2728     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
2729                 "Server built: %s", ap_get_server_built());
2730     restart_pending = shutdown_pending = 0;
2731
2732     while (!restart_pending && !shutdown_pending) {
2733         int child_slot;
2734         ap_wait_t status;
2735         int pid = wait_or_timeout(&status);
2736
2737         /* XXX: if it takes longer than 1 second for all our children
2738          * to start up and get into IDLE state then we may spawn an
2739          * extra child
2740          */
2741         if (pid >= 0) {
2742             process_child_status(pid, status);
2743             /* non-fatal death... note that it's gone in the scoreboard. */
2744             ap_sync_scoreboard_image();
2745             child_slot = find_child_by_pid(pid);
2746             if (child_slot >= 0) {
2747                 (void) ap_update_child_status(child_slot, SERVER_DEAD,
2748                                             (request_rec *) NULL);
2749                 if (remaining_children_to_start
2750                     && child_slot < ap_daemons_limit) {
2751                     /* we're still doing a 1-for-1 replacement of dead
2752                         * children with new children
2753                         */
2754                     make_child(server_conf, child_slot, time(0));
2755                     --remaining_children_to_start;
2756                 }
2757 #ifdef HAS_OTHER_CHILD
2758             }
2759             else if (reap_other_child(pid, status) == 0) {
2760                 /* handled */
2761 #endif
2762             }
2763             else if (is_graceful) {
2764                 /* Great, we've probably just lost a slot in the
2765                     * scoreboard.  Somehow we don't know about this
2766                     * child.
2767                     */
2768                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
2769                             "long lost child came home! (pid %d)", pid);
2770             }
2771             /* Don't perform idle maintenance when a child dies,
2772                 * only do it when there's a timeout.  Remember only a
2773                 * finite number of children can die, and it's pretty
2774                 * pathological for a lot to die suddenly.
2775                 */
2776             continue;
2777         }
2778         else if (remaining_children_to_start) {
2779             /* we hit a 1 second timeout in which none of the previous
2780                 * generation of children needed to be reaped... so assume
2781                 * they're all done, and pick up the slack if any is left.
2782                 */
2783             startup_children(remaining_children_to_start);
2784             remaining_children_to_start = 0;
2785             /* In any event we really shouldn't do the code below because
2786                 * few of the servers we just started are in the IDLE state
2787                 * yet, so we'd mistakenly create an extra server.
2788                 */
2789             continue;
2790         }
2791
2792         perform_idle_server_maintenance();
2793 #ifdef TPF
2794     shutdown_pending = os_check_server(tpf_server_name);
2795     ap_check_signals();
2796     sleep(1);
2797 #endif /*TPF */
2798     }
2799
2800     if (shutdown_pending) {
2801         /* Time to gracefully shut down:
2802          * Kill child processes, tell them to call child_exit, etc...
2803          */
2804         if (ap_killpg(getpgrp(), SIGTERM) < 0) {
2805             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
2806         }
2807         reclaim_child_processes(1);             /* Start with SIGTERM */
2808
2809         /* cleanup pid file on normal shutdown */
2810         {
2811             const char *pidfile = NULL;
2812             pidfile = ap_server_root_relative (pconf, ap_pid_fname);
2813             if ( pidfile != NULL && unlink(pidfile) == 0)
2814                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
2815                                 server_conf,
2816                                 "removed PID file %s (pid=%ld)",
2817                                 pidfile, (long)getpid());
2818         }
2819
2820         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2821                     "caught SIGTERM, shutting down");
2822         return 1;
2823     }
2824
2825     /* we've been told to restart */
2826     signal(SIGHUP, SIG_IGN);
2827     signal(SIGUSR1, SIG_IGN);
2828
2829     if (one_process) {
2830         /* not worth thinking about */
2831         return 1;
2832     }
2833
2834     /* advance to the next generation */
2835     /* XXX: we really need to make sure this new generation number isn't in
2836      * use by any of the children.
2837      */
2838     ++ap_my_generation;
2839     ap_scoreboard_image->global.running_generation = ap_my_generation;
2840     update_scoreboard_global();
2841
2842     if (is_graceful) {
2843 #ifndef SCOREBOARD_FILE
2844         int i;
2845 #endif
2846         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2847                     "SIGUSR1 received.  Doing graceful restart");
2848
2849         /* kill off the idle ones */
2850         if (ap_killpg(getpgrp(), SIGUSR1) < 0) {
2851             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGUSR1");
2852         }
2853 #ifndef SCOREBOARD_FILE
2854         /* This is mostly for debugging... so that we know what is still
2855             * gracefully dealing with existing request.  But we can't really
2856             * do it if we're in a SCOREBOARD_FILE because it'll cause
2857             * corruption too easily.
2858             */
2859         ap_sync_scoreboard_image();
2860         for (i = 0; i < ap_daemons_limit; ++i) {
2861             if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
2862                 ap_scoreboard_image->servers[i].status = SERVER_GRACEFUL;
2863             }
2864         }
2865 #endif
2866     }
2867     else {
2868         /* Kill 'em off */
2869         if (ap_killpg(getpgrp(), SIGHUP) < 0) {
2870             ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGHUP");
2871         }
2872         reclaim_child_processes(0);             /* Not when just starting up */
2873         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
2874                     "SIGHUP received.  Attempting to restart");
2875     }
2876
2877     if (!is_graceful) {
2878         ap_restart_time = time(NULL);
2879     }
2880
2881     return 0;
2882 }
2883
2884 static void prefork_pre_command_line(pool *pcommands)
2885 {
2886     INIT_SIGLIST();
2887 #ifdef AUX3
2888     (void) set42sig();
2889 #endif
2890     /* TODO: set one_process properly */ one_process = 0;
2891 }
2892
2893 static void prefork_pre_config(pool *pconf, pool *plog, pool *ptemp)
2894 {
2895     static int restart_num = 0;
2896
2897     one_process = ap_exists_config_define("ONE_PROCESS");
2898
2899     /* sigh, want this only the second time around */
2900     if (restart_num++ == 1) {
2901         is_graceful = 0;
2902
2903         if (!one_process) {
2904             unixd_detach();
2905         }
2906
2907         my_pid = getpid();
2908     }
2909
2910     unixd_pre_config();
2911     ap_listen_pre_config();
2912     ap_daemons_to_start = DEFAULT_START_DAEMON;
2913     ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON;
2914     ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON;
2915     ap_daemons_limit = HARD_SERVER_LIMIT;
2916     ap_pid_fname = DEFAULT_PIDLOG;
2917     ap_scoreboard_fname = DEFAULT_SCOREBOARD;
2918     ap_lock_fname = DEFAULT_LOCKFILE;
2919     ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
2920     ap_extended_status = 0;
2921
2922     ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
2923 }
2924
2925 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) 
2926 {
2927     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2928     if (err != NULL) {
2929         return err;
2930     }
2931
2932     if (cmd->server->is_virtual) {
2933         return "PidFile directive not allowed in <VirtualHost>";
2934     }
2935     ap_pid_fname = arg;
2936     return NULL;
2937 }
2938
2939 static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg) 
2940 {
2941     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2942     if (err != NULL) {
2943         return err;
2944     }
2945
2946     ap_scoreboard_fname = arg;
2947     return NULL;
2948 }
2949
2950 static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg) 
2951 {
2952     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2953     if (err != NULL) {
2954         return err;
2955     }
2956
2957     ap_lock_fname = arg;
2958     return NULL;
2959 }
2960
2961 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg) 
2962 {
2963     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2964     if (err != NULL) {
2965         return err;
2966     }
2967
2968     ap_daemons_to_start = atoi(arg);
2969     return NULL;
2970 }
2971
2972 static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2973 {
2974     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2975     if (err != NULL) {
2976         return err;
2977     }
2978
2979     ap_daemons_min_free = atoi(arg);
2980     if (ap_daemons_min_free <= 0) {
2981        fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
2982        fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
2983        fprintf(stderr, "Please read the documentation.\n");
2984        ap_daemons_min_free = 1;
2985     }
2986        
2987     return NULL;
2988 }
2989
2990 static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
2991 {
2992     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2993     if (err != NULL) {
2994         return err;
2995     }
2996
2997     ap_daemons_max_free = atoi(arg);
2998     return NULL;
2999 }
3000
3001 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) 
3002 {
3003     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3004     if (err != NULL) {
3005         return err;
3006     }
3007
3008     ap_daemons_limit = atoi(arg);
3009     if (ap_daemons_limit > HARD_SERVER_LIMIT) {
3010        fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
3011            "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
3012        fprintf(stderr, " lowering MaxClients to %d.  To increase, please "
3013            "see the\n", HARD_SERVER_LIMIT);
3014        fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
3015        ap_daemons_limit = HARD_SERVER_LIMIT;
3016     } 
3017     else if (ap_daemons_limit < 1) {
3018         fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
3019         ap_daemons_limit = 1;
3020     }
3021     return NULL;
3022 }
3023
3024 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) 
3025 {
3026     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3027     if (err != NULL) {
3028         return err;
3029     }
3030
3031     ap_max_requests_per_child = atoi(arg);
3032
3033     return NULL;
3034 }
3035
3036 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) 
3037 {
3038     struct stat finfo;
3039     const char *fname;
3040     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3041     if (err != NULL) {
3042         return err;
3043     }
3044
3045     fname = ap_server_root_relative(cmd->pool, arg);
3046     /* ZZZ change this to the AP func FileInfo*/
3047     if ((stat(fname, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
3048         return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, 
3049                           " does not exist or is not a directory", NULL);
3050     }
3051     ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
3052     return NULL;
3053 }
3054
3055 /* there are no threads in the prefork model, so the mutexes are
3056    nops. */
3057 /* TODO: make these #defines to eliminate the function call */
3058
3059 struct ap_thread_mutex {
3060     int dummy;
3061 };
3062
3063 API_EXPORT(ap_thread_mutex *) ap_thread_mutex_new(void)
3064 {
3065     return malloc(sizeof(ap_thread_mutex));
3066 }
3067
3068 API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
3069 {
3070 }
3071
3072 API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
3073 {
3074 }
3075
3076 API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
3077 {
3078     free(mtx);
3079 }
3080
3081
3082 static const command_rec prefork_cmds[] = {
3083 UNIX_DAEMON_COMMANDS
3084 LISTEN_COMMANDS
3085 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
3086     "A file for logging the server process ID"},
3087 { "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
3088     "A file for Apache to maintain runtime process management information"},
3089 { "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1,
3090     "The lockfile used when Apache needs to lock the accept() call"},
3091 { "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
3092   "Number of child processes launched at server startup" },
3093 { "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1,
3094   "Minimum number of idle children, to handle request spikes" },
3095 { "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
3096   "Maximum number of idle children" },
3097 { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
3098   "Maximum number of children alive at the same time" },
3099 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
3100   "Maximum number of requests a particular child serves before dying." },
3101 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
3102   "The location of the directory Apache changes to before dumping core" },
3103 { NULL }
3104 };
3105
3106 module MODULE_VAR_EXPORT mpm_prefork_module = {
3107     STANDARD20_MODULE_STUFF,
3108     prefork_pre_command_line,   /* pre_command_line */
3109     prefork_pre_config,         /* pre_config */
3110     NULL,                       /* post_config */
3111     NULL,                       /* open_logs */
3112     NULL,                       /* child_init */
3113     NULL,                       /* create per-directory config structure */
3114     NULL,                       /* merge per-directory config structures */
3115     NULL,                       /* create per-server config structure */
3116     NULL,                       /* merge per-server config structures */
3117     prefork_cmds,               /* command table */
3118     NULL,                       /* handlers */
3119     NULL,                       /* translate_handler */
3120     NULL,                       /* check_user_id */
3121     NULL,                       /* check auth */
3122     NULL,                       /* check access */
3123     NULL,                       /* type_checker */
3124     NULL,                       /* pre-run fixups */
3125     NULL,                       /* logger */
3126     NULL,                       /* header parser */
3127     NULL                        /* post_read_request */
3128 };