]> granicus.if.org Git - apache/blob - server/mpm/spmt_os2/spmt_os2.c
Cleanup the ZZZ comments. Basically these used to mark places where APR
[apache] / server / mpm / spmt_os2 / spmt_os2.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
60 #define CORE_PRIVATE
61 #define INCL_DOS
62 #define INCL_DOSERRORS
63
64 #include "httpd.h"
65 #include "mpm_default.h"
66 #include "http_main.h"
67 #include "http_log.h"
68 #include "http_config.h"
69 #include "http_core.h"          /* for get_remote_host */
70 #include "http_connection.h"
71 #include "scoreboard.h"
72 #include "ap_mpm.h"
73 #include "ap_listen.h"
74 #include "iol_socket.h"
75 #include "apr_portable.h"
76
77 #include <os2.h>
78 #include <stdlib.h>
79
80 /* config globals */
81
82 static int ap_max_requests_per_child=0;
83 static char *ap_pid_fname=NULL;
84 static int ap_daemons_to_start=0;
85 static int ap_daemons_min_free=0;
86 static int ap_daemons_max_free=0;
87 static int ap_daemons_limit=0;
88 static time_t ap_restart_time=0;
89 static int ap_extended_status = 0;
90
91 /*
92  * The max child slot ever assigned, preserved across restarts.  Necessary
93  * to deal with MaxClients changes across SIGUSR1 restarts.  We use this
94  * value to optimize routines that have to scan the entire scoreboard.
95  */
96 static int max_daemons_limit = -1;
97
98 static char ap_coredump_dir[MAX_STRING_LEN];
99
100 /* *Non*-shared http_main globals... */
101
102 static server_rec *server_conf;
103
104 /* one_process --- debugging mode variable; can be set from the command line
105  * with the -X flag.  If set, this gets you the child_main loop running
106  * in the process which originally started up (no detach, no make_child),
107  * which is a pretty nice debugging environment.  (You'll get a SIGHUP
108  * early in standalone_main; just continue through.  This is the server
109  * trying to kill off any child processes which it might have lying
110  * around --- Apache doesn't keep track of their pids, it just sends
111  * SIGHUP to the process group, ignoring it in the root process.
112  * Continue through and you'll be fine.).
113  */
114
115 static int one_process = 0;
116
117 #ifdef HAS_OTHER_CHILD
118 /* used to maintain list of children which aren't part of the scoreboard */
119 typedef struct other_child_rec other_child_rec;
120 struct other_child_rec {
121     other_child_rec *next;
122     int pid;
123     void (*maintenance) (int, void *, ap_wait_t);
124     void *data;
125     int write_fd;
126 };
127 static other_child_rec *other_children;
128 #endif
129
130 static ap_context_t *pconf;             /* Pool for config stuff */
131 static scoreboard *ap_scoreboard_image = NULL;
132
133 struct thread_globals {
134     int child_num;
135     ap_context_t *pchild;               /* Pool for httpd child stuff */
136     int usr1_just_die;
137 };
138
139 static struct thread_globals **ppthread_globals = NULL;
140
141 #define THREAD_GLOBAL(gvar) ((*ppthread_globals)->gvar)
142
143
144 void reinit_scoreboard(ap_context_t *p)
145 {
146     if (ap_scoreboard_image == NULL) {
147         ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
148
149         if (ap_scoreboard_image == NULL) {
150             fprintf(stderr, "Ouch! Out of memory reiniting scoreboard!\n");
151         }
152     }
153
154     memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
155 }
156
157 void cleanup_scoreboard(void)
158 {
159     ap_assert(ap_scoreboard_image);
160     free(ap_scoreboard_image);
161     ap_scoreboard_image = NULL;
162 }
163
164
165 /* a clean exit from a child with proper cleanup */
166 static void clean_child_exit(int code)
167 {
168     if (THREAD_GLOBAL(pchild)) {
169         ap_destroy_pool(THREAD_GLOBAL(pchild));
170     }
171
172     ap_scoreboard_image->servers[THREAD_GLOBAL(child_num)].thread_retval = code;
173     _endthread();
174 }
175
176
177 #if defined(USE_OS2SEM_SERIALIZED_ACCEPT)
178
179 static HMTX lock_sem = -1;
180
181 static ap_status_t accept_mutex_cleanup(void *foo)
182 {
183     DosReleaseMutexSem(lock_sem);
184     DosCloseMutexSem(lock_sem);
185     return APR_SUCCESS;
186 }
187
188 /*
189  * Initialize mutex lock.
190  * Done by each child at it's birth
191  */
192 static void accept_mutex_child_init(ap_context_t *p)
193 {
194     int rc = DosOpenMutexSem(NULL, &lock_sem);
195
196     if (rc != 0) {
197         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, server_conf,
198                     "Child cannot open lock semaphore, rc=%d", rc);
199         clean_child_exit(APEXIT_CHILDINIT);
200     } else {
201         ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
202     }
203 }
204
205 /*
206  * Initialize mutex lock.
207  * Must be safe to call this on a restart.
208  */
209 static void accept_mutex_init(ap_context_t *p)
210 {
211     int rc = DosCreateMutexSem(NULL, &lock_sem, DC_SEM_SHARED, FALSE);
212     
213     if (rc != 0) {
214         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, server_conf,
215                     "Parent cannot create lock semaphore, rc=%d", rc);
216         exit(APEXIT_INIT);
217     }
218
219     ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
220 }
221
222 static void accept_mutex_on(void)
223 {
224     int rc = DosRequestMutexSem(lock_sem, SEM_INDEFINITE_WAIT);
225
226     if (rc != 0) {
227         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, server_conf,
228                     "OS2SEM: Error %d getting accept lock. Exiting!", rc);
229         clean_child_exit(APEXIT_CHILDFATAL);
230     }
231 }
232
233 static void accept_mutex_off(void)
234 {
235     int rc = DosReleaseMutexSem(lock_sem);
236     
237     if (rc != 0) {
238         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, server_conf,
239                     "OS2SEM: Error %d freeing accept lock. Exiting!", rc);
240         clean_child_exit(APEXIT_CHILDFATAL);
241     }
242 }
243
244 #endif
245
246
247 /* On some architectures it's safe to do unserialized accept()s in the single
248  * Listen case.  But it's never safe to do it in the case where there's
249  * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
250  * when it's safe in the single Listen case.
251  */
252 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
253 #define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
254 #else
255 #define SAFE_ACCEPT(stmt) do {stmt;} while(0)
256 #endif
257
258
259 /*****************************************************************
260  * dealing with other children
261  */
262
263 #ifdef HAS_OTHER_CHILD
264 API_EXPORT(void) ap_register_other_child(int pid,
265                        void (*maintenance) (int reason, void *, ap_wait_t status),
266                           void *data, int write_fd)
267 {
268     other_child_rec *ocr;
269
270     ocr = ap_palloc(pconf, sizeof(*ocr));
271     ocr->pid = pid;
272     ocr->maintenance = maintenance;
273     ocr->data = data;
274     ocr->write_fd = write_fd;
275     ocr->next = other_children;
276     other_children = ocr;
277 }
278
279 /* note that since this can be called by a maintenance function while we're
280  * scanning the other_children list, all scanners should protect themself
281  * by loading ocr->next before calling any maintenance function.
282  */
283 API_EXPORT(void) ap_unregister_other_child(void *data)
284 {
285     other_child_rec **pocr, *nocr;
286
287     for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
288         if ((*pocr)->data == data) {
289             nocr = (*pocr)->next;
290             (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
291             *pocr = nocr;
292             /* XXX: um, well we've just wasted some space in pconf ? */
293             return;
294         }
295     }
296 }
297
298 /* test to ensure that the write_fds are all still writable, otherwise
299  * invoke the maintenance functions as appropriate */
300 static void probe_writable_fds(void)
301 {
302     fd_set writable_fds;
303     int fd_max;
304     other_child_rec *ocr, *nocr;
305     struct timeval tv;
306     int rc;
307
308     if (other_children == NULL)
309         return;
310
311     fd_max = 0;
312     FD_ZERO(&writable_fds);
313     do {
314         for (ocr = other_children; ocr; ocr = ocr->next) {
315             if (ocr->write_fd == -1)
316                 continue;
317             FD_SET(ocr->write_fd, &writable_fds);
318             if (ocr->write_fd > fd_max) {
319                 fd_max = ocr->write_fd;
320             }
321         }
322         if (fd_max == 0)
323             return;
324
325         tv.tv_sec = 0;
326         tv.tv_usec = 0;
327         rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
328     } while (rc == -1 && errno == EINTR);
329
330     if (rc == -1) {
331         /* XXX: uhh this could be really bad, we could have a bad file
332          * descriptor due to a bug in one of the maintenance routines */
333         ap_log_unixerr("probe_writable_fds", "select",
334                     "could not probe writable fds", server_conf);
335         return;
336     }
337     if (rc == 0)
338         return;
339
340     for (ocr = other_children; ocr; ocr = nocr) {
341         nocr = ocr->next;
342         if (ocr->write_fd == -1)
343             continue;
344         if (FD_ISSET(ocr->write_fd, &writable_fds))
345             continue;
346         (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
347     }
348 }
349
350 /* possibly reap an other_child, return 0 if yes, -1 if not */
351 static int reap_other_child(int pid, ap_wait_t status)
352 {
353     other_child_rec *ocr, *nocr;
354
355     for (ocr = other_children; ocr; ocr = nocr) {
356         nocr = ocr->next;
357         if (ocr->pid != pid)
358             continue;
359         ocr->pid = -1;
360         (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
361         return 0;
362     }
363     return -1;
364 }
365 #endif
366
367 API_EXPORT(int) ap_exists_scoreboard_image(void)
368 {
369     return (ap_scoreboard_image ? 1 : 0);
370 }
371
372 int ap_update_child_status(int child_num, int status, request_rec *r)
373 {
374     int old_status;
375     short_score *ss;
376
377     if (child_num < 0)
378         return -1;
379
380     ap_check_signals();
381
382     ss = &ap_scoreboard_image->servers[child_num];
383     old_status = ss->status;
384     ss->status = status;
385
386     if (ap_extended_status) {
387         if (status == SERVER_READY || status == SERVER_DEAD) {
388             /*
389              * Reset individual counters
390              */
391             if (status == SERVER_DEAD) {
392                 ss->my_access_count = 0L;
393                 ss->my_bytes_served = 0L;
394             }
395             ss->conn_count = (unsigned short) 0;
396             ss->conn_bytes = (unsigned long) 0;
397         }
398         if (r) {
399             conn_rec *c = r->connection;
400             ap_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config,
401                                   REMOTE_NOLOOKUP), sizeof(ss->client));
402             if (r->the_request == NULL) {
403                     ap_cpystrn(ss->request, "NULL", sizeof(ss->request));
404             } else if (r->parsed_uri.password == NULL) {
405                     ap_cpystrn(ss->request, r->the_request, sizeof(ss->request));
406             } else {
407                 /* Don't reveal the password in the server-status view */
408                     ap_cpystrn(ss->request, ap_pstrcat(r->pool, r->method, " ",
409                                                ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD),
410                                                r->assbackwards ? NULL : " ", r->protocol, NULL),
411                                        sizeof(ss->request));
412             }
413             ss->vhostrec =  r->server;
414         }
415     }
416
417     if (status == SERVER_STARTING && r == NULL) {
418         /* clean up the slot's vhostrec pointer (maybe re-used)
419          * and mark the slot as belonging to a new generation.
420          */
421         ss->vhostrec = NULL;
422         ap_scoreboard_image->parent[child_num].generation = ap_scoreboard_image->global.running_generation;
423     }
424
425     return old_status;
426 }
427
428 void ap_time_process_request(int child_num, int status)
429 {
430     short_score *ss;
431 #if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES)
432     struct tms tms_blk;
433 #endif
434
435     if (child_num < 0)
436         return;
437
438     ss = &ap_scoreboard_image->servers[child_num];
439
440     if (status == START_PREQUEST) {
441 #if defined(NO_GETTIMEOFDAY)
442 #ifndef NO_TIMES
443         if ((ss->start_time = times(&tms_blk)) == -1)
444 #endif /* NO_TIMES */
445             ss->start_time = (clock_t) 0;
446 #else
447         if (gettimeofday(&ss->start_time, (struct timezone *) 0) < 0)
448             ss->start_time.tv_sec =
449                 ss->start_time.tv_usec = 0L;
450 #endif
451     }
452     else if (status == STOP_PREQUEST) {
453 #if defined(NO_GETTIMEOFDAY)
454 #ifndef NO_TIMES
455         if ((ss->stop_time = times(&tms_blk)) == -1)
456 #endif
457             ss->stop_time = ss->start_time = (clock_t) 0;
458 #else
459         if (gettimeofday(&ss->stop_time, (struct timezone *) 0) < 0)
460             ss->stop_time.tv_sec =
461                 ss->stop_time.tv_usec =
462                 ss->start_time.tv_sec =
463                 ss->start_time.tv_usec = 0L;
464 #endif
465
466     }
467 }
468
469 /* TODO: call me some time */
470 static void increment_counts(int child_num, request_rec *r)
471 {
472     long int bs = 0;
473     short_score *ss;
474
475     ss = &ap_scoreboard_image->servers[child_num];
476
477     if (r->sent_bodyct)
478         ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
479
480 #ifndef NO_TIMES
481     times(&ss->times);
482 #endif
483     ss->access_count++;
484     ss->my_access_count++;
485     ss->conn_count++;
486     ss->bytes_served += (unsigned long) bs;
487     ss->my_bytes_served += (unsigned long) bs;
488     ss->conn_bytes += (unsigned long) bs;
489 }
490
491 static int find_child_by_tid(int tid)
492 {
493     int i;
494
495     for (i = 0; i < max_daemons_limit; ++i)
496         if (ap_scoreboard_image->parent[i].tid == tid)
497             return i;
498
499     return -1;
500 }
501
502 /* Finally, this routine is used by the caretaker thread to wait for
503  * a while...
504  */
505
506 /* number of calls to wait_or_timeout between writable probes */
507 #ifndef INTERVAL_OF_WRITABLE_PROBES
508 #define INTERVAL_OF_WRITABLE_PROBES 10
509 #endif
510 static int wait_or_timeout_counter;
511
512 static int wait_or_timeout(ap_wait_t *status)
513 {
514     int ret;
515     ULONG tid;
516
517     ++wait_or_timeout_counter;
518     if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
519         wait_or_timeout_counter = 0;
520 #ifdef HAS_OTHER_CHILD
521         probe_writable_fds();
522 #endif
523     }
524
525     tid = 0;
526     ret = DosWaitThread(&tid, DCWW_NOWAIT);
527
528     if (ret == 0) {
529         int child_num = find_child_by_tid(tid);
530         ap_assert( child_num > 0 );
531         *status = ap_scoreboard_image->servers[child_num].thread_retval;
532         return tid;
533     }
534     
535     DosSleep(SCOREBOARD_MAINTENANCE_INTERVAL / 1000);
536     return -1;
537 }
538
539
540 #if defined(NSIG)
541 #define NumSIG NSIG
542 #elif defined(_NSIG)
543 #define NumSIG _NSIG
544 #elif defined(__NSIG)
545 #define NumSIG __NSIG
546 #else
547 #define NumSIG 32   /* for 1998's unixes, this is still a good assumption */
548 #endif
549
550 #ifdef SYS_SIGLIST /* platform has sys_siglist[] */
551 #define INIT_SIGLIST()  /*nothing*/
552 #else /* platform has no sys_siglist[], define our own */
553 #define SYS_SIGLIST ap_sys_siglist
554 #define INIT_SIGLIST() siglist_init();
555
556 const char *ap_sys_siglist[NumSIG];
557
558 static void siglist_init(void)
559 {
560     int sig;
561
562     ap_sys_siglist[0] = "Signal 0";
563 #ifdef SIGHUP
564     ap_sys_siglist[SIGHUP] = "Hangup";
565 #endif
566 #ifdef SIGINT
567     ap_sys_siglist[SIGINT] = "Interrupt";
568 #endif
569 #ifdef SIGQUIT
570     ap_sys_siglist[SIGQUIT] = "Quit";
571 #endif
572 #ifdef SIGILL
573     ap_sys_siglist[SIGILL] = "Illegal instruction";
574 #endif
575 #ifdef SIGTRAP
576     ap_sys_siglist[SIGTRAP] = "Trace/BPT trap";
577 #endif
578 #ifdef SIGIOT
579     ap_sys_siglist[SIGIOT] = "IOT instruction";
580 #endif
581 #ifdef SIGABRT
582     ap_sys_siglist[SIGABRT] = "Abort";
583 #endif
584 #ifdef SIGEMT
585     ap_sys_siglist[SIGEMT] = "Emulator trap";
586 #endif
587 #ifdef SIGFPE
588     ap_sys_siglist[SIGFPE] = "Arithmetic exception";
589 #endif
590 #ifdef SIGKILL
591     ap_sys_siglist[SIGKILL] = "Killed";
592 #endif
593 #ifdef SIGBUS
594     ap_sys_siglist[SIGBUS] = "Bus error";
595 #endif
596 #ifdef SIGSEGV
597     ap_sys_siglist[SIGSEGV] = "Segmentation fault";
598 #endif
599 #ifdef SIGSYS
600     ap_sys_siglist[SIGSYS] = "Bad system call";
601 #endif
602 #ifdef SIGPIPE
603     ap_sys_siglist[SIGPIPE] = "Broken pipe";
604 #endif
605 #ifdef SIGALRM
606     ap_sys_siglist[SIGALRM] = "Alarm clock";
607 #endif
608 #ifdef SIGTERM
609     ap_sys_siglist[SIGTERM] = "Terminated";
610 #endif
611 #ifdef SIGUSR1
612     ap_sys_siglist[SIGUSR1] = "User defined signal 1";
613 #endif
614 #ifdef SIGUSR2
615     ap_sys_siglist[SIGUSR2] = "User defined signal 2";
616 #endif
617 #ifdef SIGCLD
618     ap_sys_siglist[SIGCLD] = "Child status change";
619 #endif
620 #ifdef SIGCHLD
621     ap_sys_siglist[SIGCHLD] = "Child status change";
622 #endif
623 #ifdef SIGPWR
624     ap_sys_siglist[SIGPWR] = "Power-fail restart";
625 #endif
626 #ifdef SIGWINCH
627     ap_sys_siglist[SIGWINCH] = "Window changed";
628 #endif
629 #ifdef SIGURG
630     ap_sys_siglist[SIGURG] = "urgent socket condition";
631 #endif
632 #ifdef SIGPOLL
633     ap_sys_siglist[SIGPOLL] = "Pollable event occurred";
634 #endif
635 #ifdef SIGIO
636     ap_sys_siglist[SIGIO] = "socket I/O possible";
637 #endif
638 #ifdef SIGSTOP
639     ap_sys_siglist[SIGSTOP] = "Stopped (signal)";
640 #endif
641 #ifdef SIGTSTP
642     ap_sys_siglist[SIGTSTP] = "Stopped";
643 #endif
644 #ifdef SIGCONT
645     ap_sys_siglist[SIGCONT] = "Continued";
646 #endif
647 #ifdef SIGTTIN
648     ap_sys_siglist[SIGTTIN] = "Stopped (tty input)";
649 #endif
650 #ifdef SIGTTOU
651     ap_sys_siglist[SIGTTOU] = "Stopped (tty output)";
652 #endif
653 #ifdef SIGVTALRM
654     ap_sys_siglist[SIGVTALRM] = "virtual timer expired";
655 #endif
656 #ifdef SIGPROF
657     ap_sys_siglist[SIGPROF] = "profiling timer expired";
658 #endif
659 #ifdef SIGXCPU
660     ap_sys_siglist[SIGXCPU] = "exceeded cpu limit";
661 #endif
662 #ifdef SIGXFSZ
663     ap_sys_siglist[SIGXFSZ] = "exceeded file size limit";
664 #endif
665     for (sig=0; sig < sizeof(ap_sys_siglist)/sizeof(ap_sys_siglist[0]); ++sig)
666         if (ap_sys_siglist[sig] == NULL)
667             ap_sys_siglist[sig] = "";
668 }
669 #endif /* platform has sys_siglist[] */
670
671
672 /* handle all varieties of core dumping signals */
673 static void sig_coredump(int sig)
674 {
675     chdir(ap_coredump_dir);
676     signal(sig, SIG_DFL);
677     kill(getpid(), sig);
678     /* At this point we've got sig blocked, because we're still inside
679      * the signal handler.  When we leave the signal handler it will
680      * be unblocked, and we'll take the signal... and coredump or whatever
681      * is appropriate for this particular Unix.  In addition the parent
682      * will see the real signal we received -- whereas if we called
683      * abort() here, the parent would only see SIGABRT.
684      */
685 }
686
687 /*****************************************************************
688  * Connection structures and accounting...
689  */
690
691 static void just_die(int sig)
692 {
693     clean_child_exit(0);
694 }
695
696
697 static void usr1_handler(int sig)
698 {
699     if (THREAD_GLOBAL(usr1_just_die)) {
700         just_die(sig);
701     }
702     ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].deferred_die = 1;
703 }
704
705 /* volatile just in case */
706 static int volatile shutdown_pending;
707 static int volatile restart_pending;
708 static int volatile is_graceful;
709
710 static void sig_term(int sig)
711 {
712     if (shutdown_pending == 1) {
713         /* Um, is this _probably_ not an error, if the user has
714          * tried to do a shutdown twice quickly, so we won't
715          * worry about reporting it.
716          */
717         return;
718     }
719     shutdown_pending = 1;
720 }
721
722 static void restart(int sig)
723 {
724     if (restart_pending == 1) {
725         /* Probably not an error - don't bother reporting it */
726         return;
727     }
728     restart_pending = 1;
729     is_graceful = sig == SIGUSR1;
730 }
731
732 static void set_signals(void)
733 {
734 #ifndef NO_USE_SIGACTION
735     struct sigaction sa;
736
737     sigemptyset(&sa.sa_mask);
738     sa.sa_flags = 0;
739
740     if (!one_process) {
741         sa.sa_handler = sig_coredump;
742 #if defined(SA_ONESHOT)
743         sa.sa_flags = SA_ONESHOT;
744 #elif defined(SA_RESETHAND)
745         sa.sa_flags = SA_RESETHAND;
746 #endif
747         if (sigaction(SIGSEGV, &sa, NULL) < 0)
748             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGSEGV)");
749 #ifdef SIGBUS
750         if (sigaction(SIGBUS, &sa, NULL) < 0)
751             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGBUS)");
752 #endif
753 #ifdef SIGABORT
754         if (sigaction(SIGABORT, &sa, NULL) < 0)
755             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGABORT)");
756 #endif
757 #ifdef SIGABRT
758         if (sigaction(SIGABRT, &sa, NULL) < 0)
759             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGABRT)");
760 #endif
761 #ifdef SIGILL
762         if (sigaction(SIGILL, &sa, NULL) < 0)
763             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGILL)");
764 #endif
765         sa.sa_flags = 0;
766     }
767     sa.sa_handler = sig_term;
768     if (sigaction(SIGTERM, &sa, NULL) < 0)
769         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGTERM)");
770 #ifdef SIGINT
771     if (sigaction(SIGINT, &sa, NULL) < 0)
772         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGINT)");
773 #endif
774 #ifdef SIGXCPU
775     sa.sa_handler = SIG_DFL;
776     if (sigaction(SIGXCPU, &sa, NULL) < 0)
777         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGXCPU)");
778 #endif
779 #ifdef SIGXFSZ
780     sa.sa_handler = SIG_DFL;
781     if (sigaction(SIGXFSZ, &sa, NULL) < 0)
782         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGXFSZ)");
783 #endif
784 #ifdef SIGPIPE
785     sa.sa_handler = SIG_IGN;
786     if (sigaction(SIGPIPE, &sa, NULL) < 0)
787         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGPIPE)");
788 #endif
789
790     /* we want to ignore HUPs and USR1 while we're busy processing one */
791     sigaddset(&sa.sa_mask, SIGHUP);
792     sigaddset(&sa.sa_mask, SIGUSR1);
793     sa.sa_handler = restart;
794     if (sigaction(SIGHUP, &sa, NULL) < 0)
795         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGHUP)");
796     if (sigaction(SIGUSR1, &sa, NULL) < 0)
797         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGUSR1)");
798 #else
799     if (!one_process) {
800         signal(SIGSEGV, sig_coredump);
801 #ifdef SIGBUS
802         signal(SIGBUS, sig_coredump);
803 #endif /* SIGBUS */
804 #ifdef SIGABORT
805         signal(SIGABORT, sig_coredump);
806 #endif /* SIGABORT */
807 #ifdef SIGABRT
808         signal(SIGABRT, sig_coredump);
809 #endif /* SIGABRT */
810 #ifdef SIGILL
811         signal(SIGILL, sig_coredump);
812 #endif /* SIGILL */
813 #ifdef SIGXCPU
814         signal(SIGXCPU, SIG_DFL);
815 #endif /* SIGXCPU */
816 #ifdef SIGXFSZ
817         signal(SIGXFSZ, SIG_DFL);
818 #endif /* SIGXFSZ */
819     }
820
821     signal(SIGTERM, sig_term);
822 #ifdef SIGHUP
823     signal(SIGHUP, restart);
824 #endif /* SIGHUP */
825 #ifdef SIGUSR1
826     signal(SIGUSR1, restart);
827 #endif /* SIGUSR1 */
828 #ifdef SIGPIPE
829     signal(SIGPIPE, SIG_IGN);
830 #endif /* SIGPIPE */
831
832 #endif
833 }
834
835 #if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
836 static void sock_disable_nagle(ap_socket_t *s)
837 {
838     /* The Nagle algorithm says that we should delay sending partial
839      * packets in hopes of getting more data.  We don't want to do
840      * this; we are not telnet.  There are bad interactions between
841      * persistent connections and Nagle's algorithm that have very severe
842      * performance penalties.  (Failing to disable Nagle is not much of a
843      * problem with simple HTTP.)
844      *
845      * In spite of these problems, failure here is not a shooting offense.
846      */
847     int just_say_no = 1;
848     ap_status_t status;
849
850     status = ap_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no, sizeof(int));
851     if (status != APR_SUCCESS) {
852         ap_log_error(APLOG_MARK, APLOG_WARNING, status, server_conf,
853                     "setsockopt: (TCP_NODELAY)");
854     }
855 }
856
857 #else
858 #define sock_disable_nagle(s)   /* NOOP */
859 #endif
860
861
862 /*****************************************************************
863  * Child process main loop.
864  */
865
866 API_EXPORT(void) ap_child_terminate(request_rec *r)
867 {
868     r->connection->keepalive = 0;
869     ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].deferred_die = 1;
870 }
871
872 int ap_graceful_stop_signalled(void)
873 {
874     if (ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].deferred_die ||
875         ap_scoreboard_image->global.running_generation != ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].generation) {
876         return 1;
877     }
878     return 0;
879 }
880
881
882
883 static int setup_listeners(ap_context_t *pchild, ap_pollfd_t **listen_poll)
884 {
885     ap_listen_rec *lr;
886     int numfds = 0;
887
888     for (lr = ap_listeners; lr; lr = lr->next) {
889         numfds++;
890     }
891
892     ap_setup_poll(listen_poll, numfds, pchild);
893
894     for (lr = ap_listeners; lr; lr = lr->next) {
895         ap_add_poll_socket(*listen_poll, lr->sd, APR_POLLIN);
896     }
897     return 0;
898 }
899
900
901
902 static void child_main(void *child_num_arg)
903 {
904     ap_listen_rec *lr = NULL;
905     ap_listen_rec *first_lr = NULL;
906     ap_context_t *ptrans;
907     conn_rec *current_conn;
908     ap_iol *iol;
909     ap_context_t *pchild;
910     parent_score *sc_parent_rec;
911     int requests_this_child = 0;
912     ap_pollfd_t *listen_poll;
913     ap_socket_t *csd = NULL;
914     int nsds, rv;
915
916     /* Disable the restart signal handlers and enable the just_die stuff.
917      * Note that since restart() just notes that a restart has been
918      * requested there's no race condition here.
919      */
920
921     set_signals(); /* signals aren't inherrited by child threads */
922     signal(SIGHUP, just_die);
923     signal(SIGUSR1, just_die);
924     signal(SIGTERM, just_die);
925
926     /* Get a sub pool for global allocations in this child, so that
927      * we can have cleanups occur when the child exits.
928      */
929     ap_create_context(&pchild, pconf);
930     *ppthread_globals = (struct thread_globals *)ap_palloc(pchild, sizeof(struct thread_globals));
931     THREAD_GLOBAL(child_num) = (int)child_num_arg;
932     sc_parent_rec = ap_scoreboard_image->parent + THREAD_GLOBAL(child_num);
933     THREAD_GLOBAL(pchild) = pchild;
934     ap_create_context(&ptrans, pchild);
935
936     if (setup_listeners(pchild, &listen_poll)) {
937         clean_child_exit(1);
938     }
939
940     /* needs to be done before we switch UIDs so we have permissions */
941     SAFE_ACCEPT(accept_mutex_child_init(pchild));
942
943     ap_child_init_hook(pchild, server_conf);
944
945     (void) ap_update_child_status(THREAD_GLOBAL(child_num), SERVER_READY, (request_rec *) NULL);
946     
947
948     signal(SIGHUP, just_die);
949     signal(SIGTERM, just_die);
950
951     while (!ap_graceful_stop_signalled()) {
952         BUFF *conn_io;
953         int srv;
954         ap_socket_t *sd;
955
956         /* Prepare to receive a SIGUSR1 due to graceful restart so that
957          * we can exit cleanly.
958          */
959         THREAD_GLOBAL(usr1_just_die) = 1;
960         signal(SIGUSR1, usr1_handler);
961
962         /*
963          * (Re)initialize this child to a pre-connection state.
964          */
965
966         current_conn = NULL;
967
968         ap_clear_pool(ptrans);
969
970         if ((ap_max_requests_per_child > 0
971              && requests_this_child++ >= ap_max_requests_per_child)) {
972             clean_child_exit(0);
973         }
974
975         (void) ap_update_child_status(THREAD_GLOBAL(child_num), SERVER_READY, (request_rec *) NULL);
976
977         /*
978          * Wait for an acceptable connection to arrive.
979          */
980
981         /* Lock around "accept", if necessary */
982         SAFE_ACCEPT(accept_mutex_on());
983
984         for (;;) {
985             if (ap_listeners->next) {
986                 /* more than one socket */
987                 srv = ap_poll(listen_poll, &nsds, -1);
988
989                 if (srv < 0 && errno != EINTR) {
990                     /* Single Unix documents select as returning errnos
991                      * EBADF, EINTR, and EINVAL... and in none of those
992                      * cases does it make sense to continue.  In fact
993                      * on Linux 2.0.x we seem to end up with EFAULT
994                      * occasionally, and we'd loop forever due to it.
995                      */
996                     ap_log_error(APLOG_MARK, APLOG_ERR, errno, server_conf, "select: (listen)");
997                     clean_child_exit(1);
998                 }
999
1000                 if (srv <= 0)
1001                     continue;
1002
1003                 /* we remember the last_lr we searched last time around so that
1004                    we don't end up starving any particular listening socket */
1005                 if (first_lr == NULL) {
1006                     first_lr = ap_listeners;
1007                 }
1008                 
1009                 lr = first_lr;
1010                 
1011                 do {
1012                     ap_int16_t event;
1013
1014                     if (!lr) {
1015                         lr = ap_listeners;
1016                     }
1017
1018                     ap_get_revents(&event, lr->sd, listen_poll);
1019
1020                     if (event == APR_POLLIN) {
1021                         first_lr = lr->next;
1022                         break;
1023                     }
1024                     lr = lr->next;
1025                 } while (lr != first_lr);
1026                 
1027                 if (lr == first_lr) {
1028                     continue;
1029                 }
1030                 sd = lr->sd;
1031             }
1032             else {
1033                 /* only one socket, just pretend we did the other stuff */
1034                 sd = ap_listeners->sd;
1035             }
1036
1037             /* if we accept() something we don't want to die, so we have to
1038              * defer the exit
1039              */
1040             THREAD_GLOBAL(usr1_just_die) = 0;
1041             for (;;) {
1042                 if (ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].deferred_die) {
1043                     /* we didn't get a socket, and we were told to die */
1044                     clean_child_exit(0);
1045                 }
1046                 rv = ap_accept(&csd, sd, ptrans);
1047                 if (rv != APR_EINTR)
1048                     break;
1049             }
1050
1051             if (rv == APR_SUCCESS)
1052                 break;          /* We have a socket ready for reading */
1053             else {
1054
1055                 /* Our old behaviour here was to continue after accept()
1056                  * errors.  But this leads us into lots of troubles
1057                  * because most of the errors are quite fatal.  For
1058                  * example, EMFILE can be caused by slow descriptor
1059                  * leaks (say in a 3rd party module, or libc).  It's
1060                  * foolish for us to continue after an EMFILE.  We also
1061                  * seem to tickle kernel bugs on some platforms which
1062                  * lead to never-ending loops here.  So it seems best
1063                  * to just exit in most cases.
1064                  */
1065                 switch (rv) {
1066 #ifdef EPROTO
1067                     /* EPROTO on certain older kernels really means
1068                      * ECONNABORTED, so we need to ignore it for them.
1069                      * See discussion in new-httpd archives nh.9701
1070                      * search for EPROTO.
1071                      *
1072                      * Also see nh.9603, search for EPROTO:
1073                      * There is potentially a bug in Solaris 2.x x<6,
1074                      * and other boxes that implement tcp sockets in
1075                      * userland (i.e. on top of STREAMS).  On these
1076                      * systems, EPROTO can actually result in a fatal
1077                      * loop.  See PR#981 for example.  It's hard to
1078                      * handle both uses of EPROTO.
1079                      */
1080                 case EPROTO:
1081 #endif
1082 #ifdef ECONNABORTED
1083                 case ECONNABORTED:
1084 #endif
1085                     /* Linux generates the rest of these, other tcp
1086                      * stacks (i.e. bsd) tend to hide them behind
1087                      * getsockopt() interfaces.  They occur when
1088                      * the net goes sour or the client disconnects
1089                      * after the three-way handshake has been done
1090                      * in the kernel but before userland has picked
1091                      * up the socket.
1092                      */
1093 #ifdef ECONNRESET
1094                 case ECONNRESET:
1095 #endif
1096 #ifdef ETIMEDOUT
1097                 case ETIMEDOUT:
1098 #endif
1099 #ifdef EHOSTUNREACH
1100                 case EHOSTUNREACH:
1101 #endif
1102 #ifdef ENETUNREACH
1103                 case ENETUNREACH:
1104 #endif
1105                     break;
1106                 default:
1107                     ap_log_error(APLOG_MARK, APLOG_ERR, rv, server_conf,
1108                                 "accept: (client socket)");
1109                     clean_child_exit(1);
1110                 }
1111             }
1112
1113             if (ap_graceful_stop_signalled()) {
1114                 clean_child_exit(0);
1115             }
1116             THREAD_GLOBAL(usr1_just_die) = 1;
1117         }
1118
1119         SAFE_ACCEPT(accept_mutex_off());        /* unlock after "accept" */
1120
1121         /* We've got a socket, let's at least process one request off the
1122          * socket before we accept a graceful restart request.  We set
1123          * the signal to ignore because we don't want to disturb any
1124          * third party code.
1125          */
1126         signal(SIGUSR1, SIG_IGN);
1127
1128         /*
1129          * We now have a connection, so set it up with the appropriate
1130          * socket options, file descriptors, and read/write buffers.
1131          */
1132
1133         sock_disable_nagle(csd);
1134
1135         iol = os2_attach_socket(csd);
1136
1137         if (iol == NULL) {
1138           ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, NULL,
1139                        "error attaching to socket");
1140             ap_close_socket(csd);
1141             continue;
1142         }
1143
1144         (void) ap_update_child_status(THREAD_GLOBAL(child_num), SERVER_BUSY_READ,
1145                                    (request_rec *) NULL);
1146
1147         conn_io = ap_bcreate(ptrans, B_RDWR);
1148         ap_bpush_iol(conn_io, iol);
1149
1150         current_conn = ap_new_apr_connection(ptrans, server_conf, conn_io, csd,
1151                                              THREAD_GLOBAL(child_num));
1152
1153         ap_process_connection(current_conn);
1154     }
1155
1156     clean_child_exit(0);
1157 }
1158
1159
1160 static int make_child(server_rec *s, int slot, time_t now)
1161 {
1162     TID tid;
1163
1164     if (slot + 1 > max_daemons_limit) {
1165         max_daemons_limit = slot + 1;
1166     }
1167
1168     if (one_process) {
1169         struct thread_globals *parent_globals = *ppthread_globals;
1170         signal(SIGHUP, just_die);
1171         signal(SIGINT, just_die);
1172 #ifdef SIGQUIT
1173         signal(SIGQUIT, SIG_DFL);
1174 #endif
1175         signal(SIGTERM, just_die);
1176         child_main((void *)slot);
1177         *ppthread_globals = parent_globals;
1178     }
1179
1180     ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL);
1181
1182     if ((tid = _beginthread(child_main, NULL,  256*1024, (void *)slot)) == -1) {
1183         ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s, "_beginthread: Unable to create new thread");
1184
1185         /* _beginthread didn't succeed. Fix the scoreboard or else
1186          * it will say SERVER_STARTING forever and ever
1187          */
1188         (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);
1189
1190         /* In case system resources are maxxed out, we don't want
1191            Apache running away with the CPU trying to _beginthread over and
1192            over and over again. */
1193         sleep(10);
1194
1195         return -1;
1196     }
1197
1198     ap_scoreboard_image->parent[slot].tid = tid;
1199     return 0;
1200 }
1201
1202
1203 /* start up a bunch of children */
1204 static void startup_children(int number_to_start)
1205 {
1206     int i;
1207     time_t now = time(0);
1208
1209     for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
1210         if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
1211             continue;
1212         }
1213         if (make_child(server_conf, i, now) < 0) {
1214             break;
1215         }
1216         --number_to_start;
1217     }
1218 }
1219
1220
1221 /*
1222  * idle_spawn_rate is the number of children that will be spawned on the
1223  * next maintenance cycle if there aren't enough idle servers.  It is
1224  * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
1225  * without the need to spawn.
1226  */
1227 static int idle_spawn_rate = 1;
1228 #ifndef MAX_SPAWN_RATE
1229 #define MAX_SPAWN_RATE  (32)
1230 #endif
1231 static int hold_off_on_exponential_spawning;
1232
1233 static void perform_idle_server_maintenance(void)
1234 {
1235     int i;
1236     int to_kill;
1237     int idle_count;
1238     short_score *ss;
1239     time_t now = time(0);
1240     int free_length;
1241     int free_slots[MAX_SPAWN_RATE];
1242     int last_non_dead;
1243     int total_non_dead;
1244
1245     /* initialize the free_list */
1246     free_length = 0;
1247
1248     to_kill = -1;
1249     idle_count = 0;
1250     last_non_dead = -1;
1251     total_non_dead = 0;
1252
1253     for (i = 0; i < ap_daemons_limit; ++i) {
1254         int status;
1255
1256         if (i >= max_daemons_limit && free_length == idle_spawn_rate)
1257             break;
1258         ss = &ap_scoreboard_image->servers[i];
1259         status = ss->status;
1260         if (status == SERVER_DEAD) {
1261             /* try to keep children numbers as low as possible */
1262             if (free_length < idle_spawn_rate) {
1263                 free_slots[free_length] = i;
1264                 ++free_length;
1265             }
1266         }
1267         else {
1268             /* We consider a starting server as idle because we started it
1269              * at least a cycle ago, and if it still hasn't finished starting
1270              * then we're just going to swamp things worse by forking more.
1271              * So we hopefully won't need to fork more if we count it.
1272              * This depends on the ordering of SERVER_READY and SERVER_STARTING.
1273              */
1274             if (status <= SERVER_READY) {
1275                 ++ idle_count;
1276                 /* always kill the highest numbered child if we have to...
1277                  * no really well thought out reason ... other than observing
1278                  * the server behaviour under linux where lower numbered children
1279                  * tend to service more hits (and hence are more likely to have
1280                  * their data in cpu caches).
1281                  */
1282                 to_kill = i;
1283             }
1284
1285             ++total_non_dead;
1286             last_non_dead = i;
1287         }
1288     }
1289     max_daemons_limit = last_non_dead + 1;
1290     if (idle_count > ap_daemons_max_free) {
1291         /* kill off one child... we use SIGUSR1 because that'll cause it to
1292          * shut down gracefully, in case it happened to pick up a request
1293          * while we were counting
1294          */
1295         ap_scoreboard_image->parent[to_kill].deferred_die = 1;
1296         idle_spawn_rate = 1;
1297     }
1298     else if (idle_count < ap_daemons_min_free) {
1299         /* terminate the free list */
1300         if (free_length == 0) {
1301             /* only report this condition once */
1302             static int reported = 0;
1303
1304             if (!reported) {
1305                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, server_conf,
1306                             "server reached MaxClients setting, consider"
1307                             " raising the MaxClients setting");
1308                 reported = 1;
1309             }
1310             idle_spawn_rate = 1;
1311         }
1312         else {
1313             if (idle_spawn_rate >= 8) {
1314                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, server_conf,
1315                     "server seems busy, (you may need "
1316                     "to increase StartServers, or Min/MaxSpareServers), "
1317                     "spawning %d children, there are %d idle, and "
1318                     "%d total children", idle_spawn_rate,
1319                     idle_count, total_non_dead);
1320             }
1321             for (i = 0; i < free_length; ++i) {
1322                 make_child(server_conf, free_slots[i], now);
1323             }
1324             /* the next time around we want to spawn twice as many if this
1325              * wasn't good enough, but not if we've just done a graceful
1326              */
1327             if (hold_off_on_exponential_spawning) {
1328                 --hold_off_on_exponential_spawning;
1329             }
1330             else if (idle_spawn_rate < MAX_SPAWN_RATE) {
1331                 idle_spawn_rate *= 2;
1332             }
1333         }
1334     }
1335     else {
1336         idle_spawn_rate = 1;
1337     }
1338 }
1339
1340
1341 static void process_child_status(int tid, ap_wait_t status)
1342 {
1343     /* Child died... if it died due to a fatal error,
1344         * we should simply bail out.
1345         */
1346     if ((WIFEXITED(status)) &&
1347         WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
1348         ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, server_conf,
1349                         "Child %d returned a Fatal error... \n"
1350                         "Apache is exiting!",
1351                         tid);
1352         exit(APEXIT_CHILDFATAL);
1353     }
1354     if (WIFSIGNALED(status)) {
1355         switch (WTERMSIG(status)) {
1356         case SIGTERM:
1357         case SIGHUP:
1358         case SIGUSR1:
1359         case SIGKILL:
1360             break;
1361         default:
1362 #ifdef SYS_SIGLIST
1363 #ifdef WCOREDUMP
1364             if (WCOREDUMP(status)) {
1365                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,
1366                              server_conf,
1367                              "child tid %d exit signal %s (%d), "
1368                              "possible coredump in %s",
1369                              tid, (WTERMSIG(status) >= NumSIG) ? "" :
1370                              SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
1371                              ap_coredump_dir);
1372             }
1373             else {
1374 #endif
1375                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,
1376                              server_conf,
1377                              "child tid %d exit signal %s (%d)", tid,
1378                              SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
1379 #ifdef WCOREDUMP
1380             }
1381 #endif
1382 #else
1383             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,
1384                          server_conf,
1385                          "child tid %d exit signal %d",
1386                          tid, WTERMSIG(status));
1387 #endif
1388         }
1389     }
1390 }
1391
1392
1393 /*****************************************************************
1394  * Executive routines.
1395  */
1396
1397 int ap_mpm_run(ap_context_t *_pconf, ap_context_t *plog, server_rec *s)
1398 {
1399     int remaining_children_to_start;
1400     int i;
1401     ap_status_t status;
1402
1403     pconf = _pconf;
1404     server_conf = s;
1405     ap_log_pid(pconf, ap_pid_fname);
1406
1407     if ((status = ap_listen_open(s->process, s->port)) != APR_SUCCESS) {
1408         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, status, s,
1409                     "no listening sockets available, shutting down");
1410         return -1;
1411     }
1412
1413     SAFE_ACCEPT(accept_mutex_init(pconf));
1414
1415     if (!is_graceful) {
1416         reinit_scoreboard(pconf);
1417     }
1418
1419     set_signals();
1420
1421     if (ppthread_globals == NULL) {
1422         if (DosAllocThreadLocalMemory(1, (PULONG *)&ppthread_globals)) {
1423             ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, server_conf,
1424                          "Error allocating thread local storage"
1425                          "Apache is exiting!");
1426         } else {
1427           *ppthread_globals = (struct thread_globals *)ap_palloc(pconf, sizeof(struct thread_globals));
1428         }
1429     }
1430
1431     if (ap_daemons_max_free < ap_daemons_min_free + 1)  /* Don't thrash... */
1432         ap_daemons_max_free = ap_daemons_min_free + 1;
1433
1434     /* If we're doing a graceful_restart then we're going to see a lot
1435         * of children exiting immediately when we get into the main loop
1436         * below (because we just sent them SIGUSR1).  This happens pretty
1437         * rapidly... and for each one that exits we'll start a new one until
1438         * we reach at least daemons_min_free.  But we may be permitted to
1439         * start more than that, so we'll just keep track of how many we're
1440         * supposed to start up without the 1 second penalty between each fork.
1441         */
1442     remaining_children_to_start = ap_daemons_to_start;
1443     if (remaining_children_to_start > ap_daemons_limit) {
1444         remaining_children_to_start = ap_daemons_limit;
1445     }
1446     if (!is_graceful) {
1447         startup_children(remaining_children_to_start);
1448         remaining_children_to_start = 0;
1449     }
1450     else {
1451         /* give the system some time to recover before kicking into
1452             * exponential mode */
1453         hold_off_on_exponential_spawning = 10;
1454     }
1455
1456     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1457                 "%s configured -- resuming normal operations",
1458                 ap_get_server_version());
1459     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, server_conf,
1460                 "Server built: %s", ap_get_server_built());
1461     restart_pending = shutdown_pending = 0;
1462
1463     while (!restart_pending && !shutdown_pending) {
1464         int child_slot;
1465         ap_wait_t status;
1466         int tid = wait_or_timeout(&status);
1467
1468         /* XXX: if it takes longer than 1 second for all our children
1469          * to start up and get into IDLE state then we may spawn an
1470          * extra child
1471          */
1472         if (tid >= 0) {
1473             process_child_status(tid, status);
1474             /* non-fatal death... note that it's gone in the scoreboard. */
1475             child_slot = find_child_by_tid(tid);
1476             if (child_slot >= 0) {
1477                 (void) ap_update_child_status(child_slot, SERVER_DEAD,
1478                                             (request_rec *) NULL);
1479                 if (remaining_children_to_start
1480                     && child_slot < ap_daemons_limit) {
1481                     /* we're still doing a 1-for-1 replacement of dead
1482                         * children with new children
1483                         */
1484                     make_child(server_conf, child_slot, time(0));
1485                     --remaining_children_to_start;
1486                 }
1487 #ifdef HAS_OTHER_CHILD
1488 /* TODO: this won't work, we waited on a thread not a process
1489             }
1490             else if (reap_other_child(pid, status) == 0) {
1491 */
1492 #endif
1493             }
1494             else if (is_graceful) {
1495                 /* Great, we've probably just lost a slot in the
1496                     * scoreboard.  Somehow we don't know about this
1497                     * child.
1498                     */
1499                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, server_conf,
1500                             "long lost child came home! (tid %d)", tid);
1501             }
1502             /* Don't perform idle maintenance when a child dies,
1503                 * only do it when there's a timeout.  Remember only a
1504                 * finite number of children can die, and it's pretty
1505                 * pathological for a lot to die suddenly.
1506                 */
1507             continue;
1508         }
1509         else if (remaining_children_to_start) {
1510             /* we hit a 1 second timeout in which none of the previous
1511                 * generation of children needed to be reaped... so assume
1512                 * they're all done, and pick up the slack if any is left.
1513                 */
1514             startup_children(remaining_children_to_start);
1515             remaining_children_to_start = 0;
1516             /* In any event we really shouldn't do the code below because
1517                 * few of the servers we just started are in the IDLE state
1518                 * yet, so we'd mistakenly create an extra server.
1519                 */
1520             continue;
1521         }
1522
1523         perform_idle_server_maintenance();
1524     }
1525
1526     if (shutdown_pending) {
1527         /* Time to gracefully shut down */
1528         const char *pidfile = NULL;
1529         int slot;
1530         TID tid;
1531         ULONG rc;
1532
1533         /* Kill off running threads */
1534         for (slot=0; slot<max_daemons_limit; slot++) {
1535             if (ap_scoreboard_image->servers[slot].status != SERVER_DEAD) {
1536                 tid = ap_scoreboard_image->parent[slot].tid;
1537                 rc = DosKillThread(tid);
1538
1539                 if (rc == 0) {
1540                     rc = DosWaitThread(&tid, DCWW_WAIT);
1541
1542                     if (rc) {
1543                         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, server_conf,
1544                                      "error %lu waiting for thread to terminate", rc);
1545                     }
1546                 } else {
1547                     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, server_conf,
1548                                  "error %lu killing thread", rc);
1549                 }
1550             }
1551         }
1552
1553         /* cleanup pid file on normal shutdown */
1554         pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1555         if ( pidfile != NULL && unlink(pidfile) == 0)
1556             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0,
1557                             server_conf,
1558                             "removed PID file %s (pid=%ld)",
1559                             pidfile, (long)getpid());
1560
1561         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1562                     "caught SIGTERM, shutting down");
1563         return 1;
1564     }
1565
1566     /* we've been told to restart */
1567     signal(SIGHUP, SIG_IGN);
1568     signal(SIGUSR1, SIG_IGN);
1569
1570     if (one_process) {
1571         /* not worth thinking about */
1572         return 1;
1573     }
1574
1575     /* advance to the next generation */
1576     /* XXX: we really need to make sure this new generation number isn't in
1577      * use by any of the children.
1578      */
1579     ++ap_scoreboard_image->global.running_generation;
1580
1581     if (is_graceful) {
1582         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1583                     "SIGUSR1 received.  Doing graceful restart");
1584
1585         /* kill off the idle ones */
1586         for (i = 0; i < ap_daemons_limit; ++i) {
1587             ap_scoreboard_image->parent[i].deferred_die = 1;
1588         }
1589
1590         /* This is mostly for debugging... so that we know what is still
1591             * gracefully dealing with existing request.  But we can't really
1592             * do it if we're in a SCOREBOARD_FILE because it'll cause
1593             * corruption too easily.
1594             */
1595         for (i = 0; i < ap_daemons_limit; ++i) {
1596             if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
1597                 ap_scoreboard_image->servers[i].status = SERVER_GRACEFUL;
1598             }
1599         }
1600     }
1601     else {
1602         /* Kill 'em off */
1603         for (i = 0; i < ap_daemons_limit; ++i) {
1604             DosKillThread(ap_scoreboard_image->parent[i].tid);
1605         }
1606         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1607                      "SIGHUP received.  Attempting to restart");
1608     }
1609
1610     if (!is_graceful) {
1611         ap_restart_time = time(NULL);
1612     }
1613
1614     return 0;
1615 }
1616
1617 static void spmt_os2_pre_config(ap_context_t *pconf, ap_context_t *plog, ap_context_t *ptemp)
1618 {
1619     one_process = !!getenv("ONE_PROCESS");
1620
1621     is_graceful = 0;
1622     ap_listen_pre_config();
1623     ap_daemons_to_start = DEFAULT_START_DAEMON;
1624     ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON;
1625     ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON;
1626     ap_daemons_limit = HARD_SERVER_LIMIT;
1627     ap_pid_fname = DEFAULT_PIDLOG;
1628     ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
1629     ap_extended_status = 0;
1630
1631     ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1632 }
1633
1634 static void spmt_os2_hooks(void)
1635 {
1636     ap_hook_pre_config(spmt_os2_pre_config,NULL,NULL,HOOK_MIDDLE);
1637     INIT_SIGLIST();
1638     /* TODO: set one_process properly */ one_process = 0;
1639 }
1640
1641 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) 
1642 {
1643     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1644     if (err != NULL) {
1645         return err;
1646     }
1647
1648     if (cmd->server->is_virtual) {
1649         return "PidFile directive not allowed in <VirtualHost>";
1650     }
1651     ap_pid_fname = arg;
1652     return NULL;
1653 }
1654
1655 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg)
1656 {
1657     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1658     if (err != NULL) {
1659         return err;
1660     }
1661
1662     ap_daemons_to_start = atoi(arg);
1663     return NULL;
1664 }
1665
1666 static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
1667 {
1668     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1669     if (err != NULL) {
1670         return err;
1671     }
1672
1673     ap_daemons_min_free = atoi(arg);
1674     if (ap_daemons_min_free <= 0) {
1675        fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
1676        fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
1677        fprintf(stderr, "Please read the documentation.\n");
1678        ap_daemons_min_free = 1;
1679     }
1680        
1681     return NULL;
1682 }
1683
1684 static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
1685 {
1686     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1687     if (err != NULL) {
1688         return err;
1689     }
1690
1691     ap_daemons_max_free = atoi(arg);
1692     return NULL;
1693 }
1694
1695 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) 
1696 {
1697     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1698     if (err != NULL) {
1699         return err;
1700     }
1701
1702     ap_daemons_limit = atoi(arg);
1703     if (ap_daemons_limit > HARD_SERVER_LIMIT) {
1704        fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
1705            "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
1706        fprintf(stderr, " lowering MaxClients to %d.  To increase, please "
1707            "see the\n", HARD_SERVER_LIMIT);
1708        fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
1709        ap_daemons_limit = HARD_SERVER_LIMIT;
1710     } 
1711     else if (ap_daemons_limit < 1) {
1712         fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
1713         ap_daemons_limit = 1;
1714     }
1715     return NULL;
1716 }
1717
1718 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) 
1719 {
1720     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1721     if (err != NULL) {
1722         return err;
1723     }
1724
1725     ap_max_requests_per_child = atoi(arg);
1726
1727     return NULL;
1728 }
1729
1730 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) 
1731 {
1732     struct stat finfo;
1733     const char *fname;
1734     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1735     if (err != NULL) {
1736         return err;
1737     }
1738
1739     fname = ap_server_root_relative(cmd->pool, arg);
1740     if ((stat(fname, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
1741         return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, 
1742                           " does not exist or is not a directory", NULL);
1743     }
1744     ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
1745     return NULL;
1746 }
1747
1748
1749 struct ap_thread_mutex {
1750     HMTX mutex_handle;
1751 };
1752
1753 API_EXPORT(ap_thread_mutex *) ap_thread_mutex_new(void)
1754 {
1755     ULONG rc;
1756     ap_thread_mutex *mutex = malloc(sizeof(ap_thread_mutex));
1757
1758     rc = DosCreateMutexSem(NULL, &mutex->mutex_handle, 0, 0);
1759     ap_assert(rc == 0);
1760     return mutex;
1761 }
1762
1763 API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
1764 {
1765     ULONG rc;
1766     rc = DosRequestMutexSem(mtx->mutex_handle, SEM_INDEFINITE_WAIT);
1767     ap_assert(rc == 0);
1768 }
1769
1770 API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
1771 {
1772     ULONG rc;
1773     rc = DosReleaseMutexSem(mtx->mutex_handle);
1774     ap_assert(rc == 0 || rc == ERROR_NOT_OWNER);
1775 }
1776
1777 API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
1778 {
1779     ap_thread_mutex_unlock(mtx);
1780     DosCloseMutexSem(mtx->mutex_handle);
1781     free(mtx);
1782 }
1783
1784 /* Stub functions until this MPM supports the connection status API */
1785
1786 API_EXPORT(void) ap_update_connection_status(long conn_id, const char *key, \
1787                                              const char *value)
1788 {
1789     /* NOP */
1790 }
1791
1792 API_EXPORT(void) ap_reset_connection_status(long conn_id)
1793 {
1794     /* NOP */
1795 }
1796
1797 static const command_rec spmt_os2_cmds[] = {
1798 LISTEN_COMMANDS
1799 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
1800     "A file for logging the server process ID"},
1801 { "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
1802   "Number of child processes launched at server startup" },
1803 { "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1,
1804   "Minimum number of idle children, to handle request spikes" },
1805 { "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
1806   "Maximum number of idle children" },
1807 { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
1808   "Maximum number of children alive at the same time" },
1809 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
1810   "Maximum number of requests a particular child serves before dying." },
1811 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
1812   "The location of the directory Apache changes to before dumping core" },
1813 { NULL }
1814 };
1815
1816 module MODULE_VAR_EXPORT mpm_spmt_os2_module = {
1817     STANDARD20_MODULE_STUFF,
1818     NULL,                       /* create per-directory config structure */
1819     NULL,                       /* merge per-directory config structures */
1820     NULL,                       /* create per-server config structure */
1821     NULL,                       /* merge per-server config structures */
1822     spmt_os2_cmds,              /* command ap_table_t */
1823     NULL,                       /* handlers */
1824     spmt_os2_hooks,             /* register_hooks */
1825 };