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