1 /* ====================================================================
2 * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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
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/)."
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
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.
30 * 6. Redistributions of any form whatsoever must retain the following
32 * "This product includes software developed by the Apache Group
33 * for use in the Apache HTTP server project (http://www.apache.org/)."
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 * ====================================================================
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/>.
62 #define INCL_DOSERRORS
65 #include "mpm_default.h"
66 #include "http_main.h"
68 #include "http_config.h"
69 #include "http_core.h" /* for get_remote_host */
70 #include "http_connection.h"
71 #include "scoreboard.h"
73 #include "ap_listen.h"
74 #include "iol_socket.h"
75 #include "apr_portable.h"
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;
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.
96 static int max_daemons_limit = -1;
98 static char ap_coredump_dir[MAX_STRING_LEN];
100 /* *Non*-shared http_main globals... */
102 static server_rec *server_conf;
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.).
115 static int one_process = 0;
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;
123 void (*maintenance) (int, void *, ap_wait_t);
127 static other_child_rec *other_children;
130 static ap_context_t *pconf; /* Pool for config stuff */
131 static scoreboard *ap_scoreboard_image = NULL;
133 struct thread_globals {
135 ap_context_t *pchild; /* Pool for httpd child stuff */
139 static struct thread_globals **ppthread_globals = NULL;
141 #define THREAD_GLOBAL(gvar) ((*ppthread_globals)->gvar)
144 void reinit_scoreboard(ap_context_t *p)
146 if (ap_scoreboard_image == NULL) {
147 ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
149 if (ap_scoreboard_image == NULL) {
150 fprintf(stderr, "Ouch! Out of memory reiniting scoreboard!\n");
154 memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
157 void cleanup_scoreboard(void)
159 ap_assert(ap_scoreboard_image);
160 free(ap_scoreboard_image);
161 ap_scoreboard_image = NULL;
165 /* a clean exit from a child with proper cleanup */
166 static void clean_child_exit(int code)
168 if (THREAD_GLOBAL(pchild)) {
169 ap_destroy_pool(THREAD_GLOBAL(pchild));
172 ap_scoreboard_image->servers[THREAD_GLOBAL(child_num)].thread_retval = code;
177 #if defined(USE_OS2SEM_SERIALIZED_ACCEPT)
179 static HMTX lock_sem = -1;
181 static ap_status_t accept_mutex_cleanup(void *foo)
183 DosReleaseMutexSem(lock_sem);
184 DosCloseMutexSem(lock_sem);
189 * Initialize mutex lock.
190 * Done by each child at it's birth
192 static void accept_mutex_child_init(ap_context_t *p)
194 int rc = DosOpenMutexSem(NULL, &lock_sem);
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);
201 ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
206 * Initialize mutex lock.
207 * Must be safe to call this on a restart.
209 static void accept_mutex_init(ap_context_t *p)
211 int rc = DosCreateMutexSem(NULL, &lock_sem, DC_SEM_SHARED, FALSE);
214 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, server_conf,
215 "Parent cannot create lock semaphore, rc=%d", rc);
219 ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup);
222 static void accept_mutex_on(void)
224 int rc = DosRequestMutexSem(lock_sem, SEM_INDEFINITE_WAIT);
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);
233 static void accept_mutex_off(void)
235 int rc = DosReleaseMutexSem(lock_sem);
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);
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.
252 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
253 #define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
255 #define SAFE_ACCEPT(stmt) do {stmt;} while(0)
259 /*****************************************************************
260 * dealing with other children
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)
268 other_child_rec *ocr;
270 ocr = ap_palloc(pconf, sizeof(*ocr));
272 ocr->maintenance = maintenance;
274 ocr->write_fd = write_fd;
275 ocr->next = other_children;
276 other_children = ocr;
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.
283 API_EXPORT(void) ap_unregister_other_child(void *data)
285 other_child_rec **pocr, *nocr;
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);
292 /* XXX: um, well we've just wasted some space in pconf ? */
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)
304 other_child_rec *ocr, *nocr;
308 if (other_children == NULL)
312 FD_ZERO(&writable_fds);
314 for (ocr = other_children; ocr; ocr = ocr->next) {
315 if (ocr->write_fd == -1)
317 FD_SET(ocr->write_fd, &writable_fds);
318 if (ocr->write_fd > fd_max) {
319 fd_max = ocr->write_fd;
327 rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
328 } while (rc == -1 && errno == EINTR);
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);
340 for (ocr = other_children; ocr; ocr = nocr) {
342 if (ocr->write_fd == -1)
344 if (FD_ISSET(ocr->write_fd, &writable_fds))
346 (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
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)
353 other_child_rec *ocr, *nocr;
355 for (ocr = other_children; ocr; ocr = nocr) {
360 (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
367 API_EXPORT(int) ap_exists_scoreboard_image(void)
369 return (ap_scoreboard_image ? 1 : 0);
372 int ap_update_child_status(int child_num, int status, request_rec *r)
382 ss = &ap_scoreboard_image->servers[child_num];
383 old_status = ss->status;
386 if (ap_extended_status) {
387 if (status == SERVER_READY || status == SERVER_DEAD) {
389 * Reset individual counters
391 if (status == SERVER_DEAD) {
392 ss->my_access_count = 0L;
393 ss->my_bytes_served = 0L;
395 ss->conn_count = (unsigned short) 0;
396 ss->conn_bytes = (unsigned long) 0;
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));
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));
413 ss->vhostrec = r->server;
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.
422 ap_scoreboard_image->parent[child_num].generation = ap_scoreboard_image->global.running_generation;
428 void ap_time_process_request(int child_num, int status)
431 #if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES)
438 ss = &ap_scoreboard_image->servers[child_num];
440 if (status == START_PREQUEST) {
441 #if defined(NO_GETTIMEOFDAY)
443 if ((ss->start_time = times(&tms_blk)) == -1)
444 #endif /* NO_TIMES */
445 ss->start_time = (clock_t) 0;
447 if (gettimeofday(&ss->start_time, (struct timezone *) 0) < 0)
448 ss->start_time.tv_sec =
449 ss->start_time.tv_usec = 0L;
452 else if (status == STOP_PREQUEST) {
453 #if defined(NO_GETTIMEOFDAY)
455 if ((ss->stop_time = times(&tms_blk)) == -1)
457 ss->stop_time = ss->start_time = (clock_t) 0;
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;
469 /* TODO: call me some time */
470 static void increment_counts(int child_num, request_rec *r)
475 ss = &ap_scoreboard_image->servers[child_num];
478 ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
484 ss->my_access_count++;
486 ss->bytes_served += (unsigned long) bs;
487 ss->my_bytes_served += (unsigned long) bs;
488 ss->conn_bytes += (unsigned long) bs;
491 static int find_child_by_tid(int tid)
495 for (i = 0; i < max_daemons_limit; ++i)
496 if (ap_scoreboard_image->parent[i].tid == tid)
502 /* Finally, this routine is used by the caretaker thread to wait for
506 /* number of calls to wait_or_timeout between writable probes */
507 #ifndef INTERVAL_OF_WRITABLE_PROBES
508 #define INTERVAL_OF_WRITABLE_PROBES 10
510 static int wait_or_timeout_counter;
512 static int wait_or_timeout(ap_wait_t *status)
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();
526 ret = DosWaitThread(&tid, DCWW_NOWAIT);
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;
535 DosSleep(SCOREBOARD_MAINTENANCE_INTERVAL / 1000);
544 #elif defined(__NSIG)
545 #define NumSIG __NSIG
547 #define NumSIG 32 /* for 1998's unixes, this is still a good assumption */
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();
556 const char *ap_sys_siglist[NumSIG];
558 static void siglist_init(void)
562 ap_sys_siglist[0] = "Signal 0";
564 ap_sys_siglist[SIGHUP] = "Hangup";
567 ap_sys_siglist[SIGINT] = "Interrupt";
570 ap_sys_siglist[SIGQUIT] = "Quit";
573 ap_sys_siglist[SIGILL] = "Illegal instruction";
576 ap_sys_siglist[SIGTRAP] = "Trace/BPT trap";
579 ap_sys_siglist[SIGIOT] = "IOT instruction";
582 ap_sys_siglist[SIGABRT] = "Abort";
585 ap_sys_siglist[SIGEMT] = "Emulator trap";
588 ap_sys_siglist[SIGFPE] = "Arithmetic exception";
591 ap_sys_siglist[SIGKILL] = "Killed";
594 ap_sys_siglist[SIGBUS] = "Bus error";
597 ap_sys_siglist[SIGSEGV] = "Segmentation fault";
600 ap_sys_siglist[SIGSYS] = "Bad system call";
603 ap_sys_siglist[SIGPIPE] = "Broken pipe";
606 ap_sys_siglist[SIGALRM] = "Alarm clock";
609 ap_sys_siglist[SIGTERM] = "Terminated";
612 ap_sys_siglist[SIGUSR1] = "User defined signal 1";
615 ap_sys_siglist[SIGUSR2] = "User defined signal 2";
618 ap_sys_siglist[SIGCLD] = "Child status change";
621 ap_sys_siglist[SIGCHLD] = "Child status change";
624 ap_sys_siglist[SIGPWR] = "Power-fail restart";
627 ap_sys_siglist[SIGWINCH] = "Window changed";
630 ap_sys_siglist[SIGURG] = "urgent socket condition";
633 ap_sys_siglist[SIGPOLL] = "Pollable event occurred";
636 ap_sys_siglist[SIGIO] = "socket I/O possible";
639 ap_sys_siglist[SIGSTOP] = "Stopped (signal)";
642 ap_sys_siglist[SIGTSTP] = "Stopped";
645 ap_sys_siglist[SIGCONT] = "Continued";
648 ap_sys_siglist[SIGTTIN] = "Stopped (tty input)";
651 ap_sys_siglist[SIGTTOU] = "Stopped (tty output)";
654 ap_sys_siglist[SIGVTALRM] = "virtual timer expired";
657 ap_sys_siglist[SIGPROF] = "profiling timer expired";
660 ap_sys_siglist[SIGXCPU] = "exceeded cpu limit";
663 ap_sys_siglist[SIGXFSZ] = "exceeded file size limit";
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] = "";
669 #endif /* platform has sys_siglist[] */
672 /* handle all varieties of core dumping signals */
673 static void sig_coredump(int sig)
675 chdir(ap_coredump_dir);
676 signal(sig, SIG_DFL);
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.
687 /*****************************************************************
688 * Connection structures and accounting...
691 static void just_die(int sig)
697 static void usr1_handler(int sig)
699 if (THREAD_GLOBAL(usr1_just_die)) {
702 ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].deferred_die = 1;
705 /* volatile just in case */
706 static int volatile shutdown_pending;
707 static int volatile restart_pending;
708 static int volatile is_graceful;
710 static void sig_term(int sig)
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.
719 shutdown_pending = 1;
722 static void restart(int sig)
724 if (restart_pending == 1) {
725 /* Probably not an error - don't bother reporting it */
729 is_graceful = sig == SIGUSR1;
732 static void set_signals(void)
734 #ifndef NO_USE_SIGACTION
737 sigemptyset(&sa.sa_mask);
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;
747 if (sigaction(SIGSEGV, &sa, NULL) < 0)
748 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGSEGV)");
750 if (sigaction(SIGBUS, &sa, NULL) < 0)
751 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGBUS)");
754 if (sigaction(SIGABORT, &sa, NULL) < 0)
755 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGABORT)");
758 if (sigaction(SIGABRT, &sa, NULL) < 0)
759 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGABRT)");
762 if (sigaction(SIGILL, &sa, NULL) < 0)
763 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGILL)");
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)");
771 if (sigaction(SIGINT, &sa, NULL) < 0)
772 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGINT)");
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)");
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)");
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)");
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)");
800 signal(SIGSEGV, sig_coredump);
802 signal(SIGBUS, sig_coredump);
805 signal(SIGABORT, sig_coredump);
806 #endif /* SIGABORT */
808 signal(SIGABRT, sig_coredump);
811 signal(SIGILL, sig_coredump);
814 signal(SIGXCPU, SIG_DFL);
817 signal(SIGXFSZ, SIG_DFL);
821 signal(SIGTERM, sig_term);
823 signal(SIGHUP, restart);
826 signal(SIGUSR1, restart);
829 signal(SIGPIPE, SIG_IGN);
835 #if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
836 static void sock_disable_nagle(ap_socket_t *s)
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.)
845 * In spite of these problems, failure here is not a shooting offense.
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)");
858 #define sock_disable_nagle(s) /* NOOP */
862 /*****************************************************************
863 * Child process main loop.
866 API_EXPORT(void) ap_child_terminate(request_rec *r)
868 r->connection->keepalive = 0;
869 ap_scoreboard_image->parent[THREAD_GLOBAL(child_num)].deferred_die = 1;
872 int ap_graceful_stop_signalled(void)
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) {
883 static int setup_listeners(ap_context_t *pchild, ap_pollfd_t **listen_poll)
888 for (lr = ap_listeners; lr; lr = lr->next) {
892 ap_setup_poll(listen_poll, numfds, pchild);
894 for (lr = ap_listeners; lr; lr = lr->next) {
895 ap_add_poll_socket(*listen_poll, lr->sd, APR_POLLIN);
902 static void child_main(void *child_num_arg)
904 ap_listen_rec *lr = NULL;
905 ap_listen_rec *first_lr = NULL;
906 ap_context_t *ptrans;
907 conn_rec *current_conn;
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;
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.
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);
926 /* Get a sub pool for global allocations in this child, so that
927 * we can have cleanups occur when the child exits.
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);
936 if (setup_listeners(pchild, &listen_poll)) {
940 /* needs to be done before we switch UIDs so we have permissions */
941 SAFE_ACCEPT(accept_mutex_child_init(pchild));
943 ap_child_init_hook(pchild, server_conf);
945 (void) ap_update_child_status(THREAD_GLOBAL(child_num), SERVER_READY, (request_rec *) NULL);
948 signal(SIGHUP, just_die);
949 signal(SIGTERM, just_die);
951 while (!ap_graceful_stop_signalled()) {
956 /* Prepare to receive a SIGUSR1 due to graceful restart so that
957 * we can exit cleanly.
959 THREAD_GLOBAL(usr1_just_die) = 1;
960 signal(SIGUSR1, usr1_handler);
963 * (Re)initialize this child to a pre-connection state.
968 ap_clear_pool(ptrans);
970 if ((ap_max_requests_per_child > 0
971 && requests_this_child++ >= ap_max_requests_per_child)) {
975 (void) ap_update_child_status(THREAD_GLOBAL(child_num), SERVER_READY, (request_rec *) NULL);
978 * Wait for an acceptable connection to arrive.
981 /* Lock around "accept", if necessary */
982 SAFE_ACCEPT(accept_mutex_on());
985 if (ap_listeners->next) {
986 /* more than one socket */
987 srv = ap_poll(listen_poll, &nsds, -1);
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.
996 ap_log_error(APLOG_MARK, APLOG_ERR, errno, server_conf, "select: (listen)");
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;
1018 ap_get_revents(&event, lr->sd, listen_poll);
1020 if (event == APR_POLLIN) {
1021 first_lr = lr->next;
1025 } while (lr != first_lr);
1027 if (lr == first_lr) {
1033 /* only one socket, just pretend we did the other stuff */
1034 sd = ap_listeners->sd;
1037 /* if we accept() something we don't want to die, so we have to
1040 THREAD_GLOBAL(usr1_just_die) = 0;
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);
1046 rv = ap_accept(&csd, sd, ptrans);
1047 if (rv != APR_EINTR)
1051 if (rv == APR_SUCCESS)
1052 break; /* We have a socket ready for reading */
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.
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.
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.
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
1107 ap_log_error(APLOG_MARK, APLOG_ERR, rv, server_conf,
1108 "accept: (client socket)");
1109 clean_child_exit(1);
1113 if (ap_graceful_stop_signalled()) {
1114 clean_child_exit(0);
1116 THREAD_GLOBAL(usr1_just_die) = 1;
1119 SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
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
1126 signal(SIGUSR1, SIG_IGN);
1129 * We now have a connection, so set it up with the appropriate
1130 * socket options, file descriptors, and read/write buffers.
1133 sock_disable_nagle(csd);
1135 iol = os2_attach_socket(csd);
1138 ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, NULL,
1139 "error attaching to socket");
1140 ap_close_socket(csd);
1144 (void) ap_update_child_status(THREAD_GLOBAL(child_num), SERVER_BUSY_READ,
1145 (request_rec *) NULL);
1147 conn_io = ap_bcreate(ptrans, B_RDWR);
1148 ap_bpush_iol(conn_io, iol);
1150 current_conn = ap_new_apr_connection(ptrans, server_conf, conn_io, csd,
1151 THREAD_GLOBAL(child_num));
1153 ap_process_connection(current_conn);
1156 clean_child_exit(0);
1160 static int make_child(server_rec *s, int slot, time_t now)
1164 if (slot + 1 > max_daemons_limit) {
1165 max_daemons_limit = slot + 1;
1169 struct thread_globals *parent_globals = *ppthread_globals;
1170 signal(SIGHUP, just_die);
1171 signal(SIGINT, just_die);
1173 signal(SIGQUIT, SIG_DFL);
1175 signal(SIGTERM, just_die);
1176 child_main((void *)slot);
1177 *ppthread_globals = parent_globals;
1180 ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL);
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");
1185 /* _beginthread didn't succeed. Fix the scoreboard or else
1186 * it will say SERVER_STARTING forever and ever
1188 (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);
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. */
1198 ap_scoreboard_image->parent[slot].tid = tid;
1203 /* start up a bunch of children */
1204 static void startup_children(int number_to_start)
1207 time_t now = time(0);
1209 for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
1210 if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
1213 if (make_child(server_conf, i, now) < 0) {
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.
1227 static int idle_spawn_rate = 1;
1228 #ifndef MAX_SPAWN_RATE
1229 #define MAX_SPAWN_RATE (32)
1231 static int hold_off_on_exponential_spawning;
1233 static void perform_idle_server_maintenance(void)
1239 time_t now = time(0);
1241 int free_slots[MAX_SPAWN_RATE];
1245 /* initialize the free_list */
1253 for (i = 0; i < ap_daemons_limit; ++i) {
1256 if (i >= max_daemons_limit && free_length == idle_spawn_rate)
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;
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.
1274 if (status <= SERVER_READY) {
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).
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
1295 ap_scoreboard_image->parent[to_kill].deferred_die = 1;
1296 idle_spawn_rate = 1;
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;
1305 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, server_conf,
1306 "server reached MaxClients setting, consider"
1307 " raising the MaxClients setting");
1310 idle_spawn_rate = 1;
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);
1321 for (i = 0; i < free_length; ++i) {
1322 make_child(server_conf, free_slots[i], now);
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
1327 if (hold_off_on_exponential_spawning) {
1328 --hold_off_on_exponential_spawning;
1330 else if (idle_spawn_rate < MAX_SPAWN_RATE) {
1331 idle_spawn_rate *= 2;
1336 idle_spawn_rate = 1;
1341 static void process_child_status(int tid, ap_wait_t status)
1343 /* Child died... if it died due to a fatal error,
1344 * we should simply bail out.
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!",
1352 exit(APEXIT_CHILDFATAL);
1354 if (WIFSIGNALED(status)) {
1355 switch (WTERMSIG(status)) {
1364 if (WCOREDUMP(status)) {
1365 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,
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),
1375 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,
1377 "child tid %d exit signal %s (%d)", tid,
1378 SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
1383 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,
1385 "child tid %d exit signal %d",
1386 tid, WTERMSIG(status));
1393 /*****************************************************************
1394 * Executive routines.
1397 int ap_mpm_run(ap_context_t *_pconf, ap_context_t *plog, server_rec *s)
1399 int remaining_children_to_start;
1405 ap_log_pid(pconf, ap_pid_fname);
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");
1413 SAFE_ACCEPT(accept_mutex_init(pconf));
1416 reinit_scoreboard(pconf);
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!");
1427 *ppthread_globals = (struct thread_globals *)ap_palloc(pconf, sizeof(struct thread_globals));
1431 if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */
1432 ap_daemons_max_free = ap_daemons_min_free + 1;
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.
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;
1447 startup_children(remaining_children_to_start);
1448 remaining_children_to_start = 0;
1451 /* give the system some time to recover before kicking into
1452 * exponential mode */
1453 hold_off_on_exponential_spawning = 10;
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;
1463 while (!restart_pending && !shutdown_pending) {
1466 int tid = wait_or_timeout(&status);
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
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
1484 make_child(server_conf, child_slot, time(0));
1485 --remaining_children_to_start;
1487 #ifdef HAS_OTHER_CHILD
1488 /* TODO: this won't work, we waited on a thread not a process
1490 else if (reap_other_child(pid, status) == 0) {
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
1499 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, server_conf,
1500 "long lost child came home! (tid %d)", tid);
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.
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.
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.
1523 perform_idle_server_maintenance();
1526 if (shutdown_pending) {
1527 /* Time to gracefully shut down */
1528 const char *pidfile = NULL;
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);
1540 rc = DosWaitThread(&tid, DCWW_WAIT);
1543 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, server_conf,
1544 "error %lu waiting for thread to terminate", rc);
1547 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, server_conf,
1548 "error %lu killing thread", rc);
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,
1558 "removed PID file %s (pid=%ld)",
1559 pidfile, (long)getpid());
1561 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1562 "caught SIGTERM, shutting down");
1566 /* we've been told to restart */
1567 signal(SIGHUP, SIG_IGN);
1568 signal(SIGUSR1, SIG_IGN);
1571 /* not worth thinking about */
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.
1579 ++ap_scoreboard_image->global.running_generation;
1582 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1583 "SIGUSR1 received. Doing graceful restart");
1585 /* kill off the idle ones */
1586 for (i = 0; i < ap_daemons_limit; ++i) {
1587 ap_scoreboard_image->parent[i].deferred_die = 1;
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.
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;
1603 for (i = 0; i < ap_daemons_limit; ++i) {
1604 DosKillThread(ap_scoreboard_image->parent[i].tid);
1606 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, server_conf,
1607 "SIGHUP received. Attempting to restart");
1611 ap_restart_time = time(NULL);
1617 static void spmt_os2_pre_config(ap_context_t *pconf, ap_context_t *plog, ap_context_t *ptemp)
1619 one_process = !!getenv("ONE_PROCESS");
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;
1631 ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1634 static void spmt_os2_hooks(void)
1636 ap_hook_pre_config(spmt_os2_pre_config,NULL,NULL,HOOK_MIDDLE);
1638 /* TODO: set one_process properly */ one_process = 0;
1641 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg)
1643 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1648 if (cmd->server->is_virtual) {
1649 return "PidFile directive not allowed in <VirtualHost>";
1655 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg)
1657 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1662 ap_daemons_to_start = atoi(arg);
1666 static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
1668 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
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;
1684 static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
1686 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1691 ap_daemons_max_free = atoi(arg);
1695 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg)
1697 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
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;
1711 else if (ap_daemons_limit < 1) {
1712 fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
1713 ap_daemons_limit = 1;
1718 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg)
1720 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1725 ap_max_requests_per_child = atoi(arg);
1730 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg)
1734 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
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);
1744 ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
1749 struct ap_thread_mutex {
1753 API_EXPORT(ap_thread_mutex *) ap_thread_mutex_new(void)
1756 ap_thread_mutex *mutex = malloc(sizeof(ap_thread_mutex));
1758 rc = DosCreateMutexSem(NULL, &mutex->mutex_handle, 0, 0);
1763 API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
1766 rc = DosRequestMutexSem(mtx->mutex_handle, SEM_INDEFINITE_WAIT);
1770 API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
1773 rc = DosReleaseMutexSem(mtx->mutex_handle);
1774 ap_assert(rc == 0 || rc == ERROR_NOT_OWNER);
1777 API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
1779 ap_thread_mutex_unlock(mtx);
1780 DosCloseMutexSem(mtx->mutex_handle);
1784 /* Stub functions until this MPM supports the connection status API */
1786 API_EXPORT(void) ap_update_connection_status(long conn_id, const char *key, \
1792 API_EXPORT(void) ap_reset_connection_status(long conn_id)
1797 static const command_rec spmt_os2_cmds[] = {
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" },
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 */