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