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/>.
58 /* This module is effectivly mpmt_pthread much modified to
59 * allow it work on BeOS. It's stable and works OK.
64 #include "apr_portable.h"
66 #include "http_main.h"
68 #include "http_config.h" /* for read_config */
69 #include "http_core.h" /* for get_remote_host */
70 #include "http_connection.h"
73 #include "iol_socket.h"
74 #include "ap_listen.h"
75 #include "scoreboard.h"
76 #include "acceptlock.h"
81 * Actual definitions of config globals
84 int ap_threads_per_child=0; /* Worker threads per child */
85 int ap_max_requests_per_child=0;
86 static char *ap_pid_fname=NULL;
87 static char *ap_scoreboard_fname=NULL;
88 static int ap_daemons_to_start=0;
89 static int min_spare_threads=0;
90 static int max_spare_threads=0;
91 static int ap_daemons_limit=0;
92 static time_t ap_restart_time=0;
93 API_VAR_EXPORT int ap_extended_status = 0;
94 static int workers_may_exit = 0;
95 static int requests_this_child;
96 static int num_listenfds = 0;
97 static struct pollfd *listenfds;
99 /* The structure used to pass unique initialization info to each thread */
104 ap_context_t *tpool; /* "pthread" would be confusing */
107 #define SERVER_DEAD 0
108 #define SERVER_DYING 1
109 #define SERVER_ALIVE 2
113 unsigned char status;
114 } child_table[HARD_SERVER_LIMIT];
117 #define SAFE_ACCEPT(stmt) do {if (ap_listeners->next != NULL) {stmt;}} while (0)
119 #define SAFE_ACCEPT(stmt) do {stmt;} while (0)
123 * The max child slot ever assigned, preserved across restarts. Necessary
124 * to deal with MaxClients changes across SIGWINCH restarts. We use this
125 * value to optimize routines that have to scan the entire scoreboard.
127 int max_daemons_limit = -1;
128 static char ap_coredump_dir[MAX_STRING_LEN];
129 port_id port_of_death;
131 /* *Non*-shared http_main globals... */
133 static server_rec *server_conf;
135 /* one_process --- debugging mode variable; can be set from the command line
136 * with the -X flag. If set, this gets you the child_main loop running
137 * in the process which originally started up (no detach, no make_child),
138 * which is a pretty nice debugging environment. (You'll get a SIGHUP
139 * early in standalone_main; just continue through. This is the server
140 * trying to kill off any child processes which it might have lying
141 * around --- Apache doesn't keep track of their pids, it just sends
142 * SIGHUP to the process group, ignoring it in the root process.
143 * Continue through and you'll be fine.).
146 static int one_process = 0;
149 int raise_sigstop_flags;
152 #ifdef HAS_OTHER_CHILD
153 /* used to maintain list of children which aren't part of the scoreboard */
154 typedef struct other_child_rec other_child_rec;
155 struct other_child_rec {
156 other_child_rec *next;
158 void (*maintenance) (int, void *, ap_wait_t);
162 static other_child_rec *other_children;
165 static ap_context_t *pconf; /* Pool for config stuff */
166 static ap_context_t *pchild; /* Pool for httpd child stuff */
168 static int my_pid; /* Linux getpid() doesn't work except in main thread. Use
170 /* Keep track of the number of worker threads currently active */
171 static int worker_thread_count;
172 static be_mutex_t worker_thread_count_mutex;
174 /* Global, alas, so http_core can talk to us */
175 enum server_token_type ap_server_tokens = SrvTk_FULL;
177 API_EXPORT(const server_rec *) ap_get_server_conf(void)
179 return (server_conf);
182 API_EXPORT(int) ap_get_max_daemons(void)
184 return max_daemons_limit;
187 /* a clean exit from a child with proper cleanup
188 static void clean_child_exit(int code) __attribute__ ((noreturn)); */
189 void clean_child_exit(int code)
192 ap_destroy_pool(pchild);
197 /*****************************************************************
198 * dealing with other children
201 #ifdef HAS_OTHER_CHILD
202 API_EXPORT(void) ap_register_other_child(int pid,
203 void (*maintenance) (int reason, void *, ap_wait_t status),
204 void *data, int write_fd)
206 other_child_rec *ocr;
208 ocr = ap_palloc(pconf, sizeof(*ocr));
210 ocr->maintenance = maintenance;
212 ocr->write_fd = write_fd;
213 ocr->next = other_children;
214 other_children = ocr;
217 /* note that since this can be called by a maintenance function while we're
218 * scanning the other_children list, all scanners should protect themself
219 * by loading ocr->next before calling any maintenance function.
221 API_EXPORT(void) ap_unregister_other_child(void *data)
223 other_child_rec **pocr, *nocr;
225 for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
226 if ((*pocr)->data == data) {
227 nocr = (*pocr)->next;
228 (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
230 /* XXX: um, well we've just wasted some space in pconf ? */
236 /* test to ensure that the write_fds are all still writable, otherwise
237 * invoke the maintenance functions as appropriate */
238 static void probe_writable_fds(void)
244 other_child_rec *ocr, *nocr;
248 if (other_children == NULL)
252 FD_ZERO(&writable_fds);
254 for (ocr = other_children; ocr; ocr = ocr->next) {
255 if (ocr->write_fd == -1)
257 FD_SET(ocr->write_fd, &writable_fds);
258 if (ocr->write_fd > fd_max) {
259 fd_max = ocr->write_fd;
267 rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
268 } while (rc == -1 && errno == EINTR);
271 /* XXX: uhh this could be really bad, we could have a bad file
272 * descriptor due to a bug in one of the maintenance routines */
273 ap_log_unixerr("probe_writable_fds", "select",
274 "could not probe writable fds", server_conf);
280 for (ocr = other_children; ocr; ocr = nocr) {
282 if (ocr->write_fd == -1)
284 if (FD_ISSET(ocr->write_fd, &writable_fds))
286 (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
291 /* possibly reap an other_child, return 0 if yes, -1 if not */
292 static int reap_other_child(int pid, ap_wait_t status)
294 other_child_rec *ocr, *nocr;
296 for (ocr = other_children; ocr; ocr = nocr) {
301 (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
308 static void reclaim_child_processes(int terminate)
311 long int waittime = 1024 * 16; /* in usecs */
315 #ifdef HAS_OTHER_CHILD
316 other_child_rec *ocr, *nocr;
319 for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
320 /* don't want to hold up progress any more than
321 * necessary, but we need to allow children a few moments to exit.
322 * Set delay with an exponential backoff.
324 tv.tv_sec = waittime / 1000000;
325 tv.tv_usec = waittime % 1000000;
326 waittime = waittime * 4;
327 ap_select(0, NULL, NULL, NULL, &tv);
329 /* now see who is done */
331 for (i = 0; i < max_daemons_limit; ++i) {
333 if (child_table[i].status == SERVER_DEAD)
336 pid = child_table[i].pid;
338 waitret = waitpid(pid, &status, WNOHANG);
339 if (waitret == pid || waitret == -1) {
340 child_table[i].status = SERVER_DEAD;
353 /* ok, now it's being annoying */
354 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
356 "child process %d still did not exit, sending a SIGTERM",
362 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, errno, server_conf,
363 "child process %d still did not exit, sending a SIGKILL",
368 /* gave it our best shot, but alas... If this really
369 * is a child we are trying to kill and it really hasn't
370 * exited, we will likely fail to bind to the port
373 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, errno, server_conf,
374 "could not make child process %d exit, "
375 "attempting to continue anyway", pid);
379 #ifdef HAS_OTHER_CHILD
380 for (ocr = other_children; ocr; ocr = nocr) {
385 waitret = waitpid(ocr->pid, &status, WNOHANG);
386 if (waitret == ocr->pid) {
388 (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
390 else if (waitret == 0) {
391 (*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
394 else if (waitret == -1) {
395 /* uh what the heck? they didn't call unregister? */
397 (*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
402 /* nothing left to wait for */
408 /* Finally, this routine is used by the caretaker process to wait for
412 /* number of calls to wait_or_timeout between writable probes */
413 #ifndef INTERVAL_OF_WRITABLE_PROBES
414 #define INTERVAL_OF_WRITABLE_PROBES 10
416 static int wait_or_timeout_counter;
418 static int wait_or_timeout(ap_wait_t *status)
423 ++wait_or_timeout_counter;
424 if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
425 wait_or_timeout_counter = 0;
426 #ifdef HAS_OTHER_CHILD
427 probe_writable_fds();
430 ret = waitpid(-1, status, WNOHANG);
431 if (ret == -1 && errno == EINTR) {
437 tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
438 tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
439 ap_select(0, NULL, NULL, NULL, &tv);
443 /* handle all varieties of core dumping signals */
444 static void sig_coredump(int sig)
446 chdir(ap_coredump_dir);
447 signal(sig, SIG_DFL);
449 /* At this point we've got sig blocked, because we're still inside
450 * the signal handler. When we leave the signal handler it will
451 * be unblocked, and we'll take the signal... and coredump or whatever
452 * is appropriate for this particular Unix. In addition the parent
453 * will see the real signal we received -- whereas if we called
454 * abort() here, the parent would only see SIGABRT.
458 static void just_die(int sig)
463 /*****************************************************************
464 * Connection structures and accounting...
467 /* volatile just in case */
468 static int volatile shutdown_pending;
469 static int volatile restart_pending;
470 static int volatile is_graceful;
473 * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
474 * functions to initiate shutdown or restart without relying on signals.
475 * Previously this was initiated in sig_term() and restart() signal handlers,
476 * but we want to be able to start a shutdown/restart from other sources --
477 * e.g. on Win32, from the service manager. Now the service manager can
478 * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
479 * these functions can also be called by the child processes, since global
480 * variables are no longer used to pass on the required action to the parent.
482 * These should only be called from the parent process itself, since the
483 * parent process will use the shutdown_pending and restart_pending variables
484 * to determine whether to shutdown or restart. The child process should
485 * call signal_parent() directly to tell the parent to die -- this will
486 * cause neither of those variable to be set, which the parent will
487 * assume means something serious is wrong (which it will be, for the
488 * child to force an exit) and so do an exit anyway.
491 void ap_start_shutdown(void)
493 if (shutdown_pending == 1) {
494 /* Um, is this _probably_ not an error, if the user has
495 * tried to do a shutdown twice quickly, so we won't
496 * worry about reporting it.
500 shutdown_pending = 1;
503 /* do a graceful restart if graceful == 1 */
504 void ap_start_restart(int graceful)
507 if (restart_pending == 1) {
508 /* Probably not an error - don't bother reporting it */
512 is_graceful = graceful;
515 static void sig_term(int sig)
520 static void restart(int sig)
522 ap_start_restart(sig == SIGWINCH);
525 static void set_signals(void)
529 sigemptyset(&sa.sa_mask);
533 sa.sa_handler = sig_coredump;
535 if (sigaction(SIGSEGV, &sa, NULL) < 0)
536 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGSEGV)");
537 if (sigaction(SIGBUS, &sa, NULL) < 0)
538 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGBUS)");
539 if (sigaction(SIGABRT, &sa, NULL) < 0)
540 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGABRT)");
541 if (sigaction(SIGILL, &sa, NULL) < 0)
542 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGILL)");
545 sa.sa_handler = sig_term;
546 if (sigaction(SIGTERM, &sa, NULL) < 0)
547 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGTERM)");
548 if (sigaction(SIGINT, &sa, NULL) < 0)
549 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGINT)");
551 sa.sa_handler = SIG_IGN;
552 if (sigaction(SIGPIPE, &sa, NULL) < 0)
553 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGPIPE)");
555 /* we want to ignore HUPs and WINCH while we're busy processing one */
556 sigaddset(&sa.sa_mask, SIGHUP);
557 sigaddset(&sa.sa_mask, SIGWINCH);
558 sa.sa_handler = restart;
559 if (sigaction(SIGHUP, &sa, NULL) < 0)
560 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGHUP)");
561 if (sigaction(SIGWINCH, &sa, NULL) < 0)
562 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf, "sigaction(SIGWINCH)");
565 static void process_child_status(int pid, ap_wait_t status)
567 /* Child died... if it died due to a fatal error,
568 * we should simply bail out.
570 if ((WIFEXITED(status)) &&
571 WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
572 ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, errno, server_conf,
573 "Child %d returned a Fatal error... \n"
574 "Apache is exiting!",
576 exit(APEXIT_CHILDFATAL);
578 if (WIFSIGNALED(status)) {
579 switch (WTERMSIG(status)) {
588 if (WCOREDUMP(status)) {
589 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
591 "child pid %d exit signal %s (%d), "
592 "possible coredump in %s",
593 pid, (WTERMSIG(status) >= NumSIG) ? "" :
594 SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
599 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
601 "child pid %d exit signal %s (%d)", pid,
602 SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
607 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
609 "child pid %d exit signal %d",
610 pid, WTERMSIG(status));
616 static int setup_listeners(server_rec *s)
619 int num_listeners = 0;
620 if (ap_listen_open(s->process, s->port)) {
623 for (lr = ap_listeners; lr; lr = lr->next) {
626 return num_listeners;
629 /*****************************************************************
630 * Here follows a long bunch of generic server bookkeeping stuff...
633 #define sock_disable_nagle(s) /* NOOP */
635 int ap_graceful_stop_signalled(void)
637 /* XXX - Does this really work? - Manoj */
641 /*****************************************************************
642 * Child process main loop.
645 static void process_socket(ap_context_t *p, ap_socket_t *sock, int my_child_num, int my_thread_num)
648 conn_rec *current_conn;
650 long conn_id = my_child_num * HARD_THREAD_LIMIT + my_thread_num;
653 iol = beos_attach_socket(sock);
655 if (errno == EBADF) {
656 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, NULL,
657 "filedescriptor (%u) larger than FD_SETSIZE (%u) "
658 "found, you probably need to rebuild Apache with a "
659 "larger FD_SETSIZE", csd, FD_SETSIZE);
662 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, NULL,
663 "error attaching to socket");
665 ap_close_socket(sock);
669 conn_io = ap_bcreate(p, B_RDWR);
670 ap_bpush_iol(conn_io, iol);
672 current_conn = ap_new_apr_connection(p, server_conf, conn_io, sock,
675 ap_process_connection(current_conn);
678 static int32 worker_thread(void * dummy)
680 proc_info * ti = dummy;
681 int process_slot = ti->pid;
682 int thread_slot = ti->tid;
683 ap_context_t *tpool = ti->tpool;
684 struct sockaddr sa_client;
685 ap_socket_t *csd = NULL;
686 ap_context_t *ptrans; /* Pool for per-transaction stuff */
687 ap_socket_t *sd = NULL;
689 int curr_pollfd, last_pollfd = 0;
695 /* block the signals for this thread */
696 sigfillset(&sig_mask);
697 sigprocmask(SIG_BLOCK, &sig_mask, NULL);
699 ap_create_context(&ptrans, tpool);
701 be_mutex_lock(&worker_thread_count_mutex);
702 worker_thread_count++;
703 be_mutex_unlock(&worker_thread_count_mutex);
705 /* TODO: Switch to a system where threads reuse the results from earlier
706 poll calls - manoj */
707 while (!workers_may_exit) {
708 workers_may_exit |= (ap_max_requests_per_child != 0) && (requests_this_child <= 0);
709 if (workers_may_exit) break;
711 SAFE_ACCEPT(intra_mutex_on(0));
712 if (workers_may_exit) {
713 SAFE_ACCEPT(intra_mutex_off(0));
716 SAFE_ACCEPT(accept_mutex_on(0));
717 while (!workers_may_exit) {
718 srv = poll(listenfds, num_listenfds + 1, -1);
720 if (errno == EINTR) {
724 /* poll() will only return errors in catastrophic
725 * circumstances. Let's try exiting gracefully, for now. */
726 ap_log_error(APLOG_MARK, APLOG_ERR,errno, (const server_rec *)
727 ap_get_server_conf(), "poll: (listen)");
728 workers_may_exit = 1;
731 if (workers_may_exit) break;
733 if (num_listenfds == 1) {
734 sd = ap_listeners->sd;
738 /* find a listener */
739 curr_pollfd = last_pollfd;
742 if (curr_pollfd > num_listenfds) {
745 /* XXX: Should we check for POLLERR? */
746 if (listenfds[curr_pollfd].revents & POLLIN) {
747 last_pollfd = curr_pollfd;
748 ap_put_os_sock(&sd, &listenfds[curr_pollfd].fd, tpool);
751 } while (curr_pollfd != last_pollfd);
755 if (!workers_may_exit) {
756 ap_accept(&csd, sd, ptrans);
757 SAFE_ACCEPT(accept_mutex_off(0));
758 SAFE_ACCEPT(intra_mutex_off(0));
759 process_socket(ptrans, csd, process_slot,
761 requests_this_child--;
764 SAFE_ACCEPT(accept_mutex_off(0));
765 SAFE_ACCEPT(intra_mutex_off(0));
768 ap_clear_pool(ptrans);
771 ap_destroy_pool(tpool);
772 be_mutex_lock(&worker_thread_count_mutex);
773 worker_thread_count--;
774 if (worker_thread_count == 0) {
775 /* All the threads have exited, now finish the shutdown process
776 * by signalling the sigwait thread */
777 kill(my_pid, SIGTERM);
779 be_mutex_unlock(&worker_thread_count_mutex);
785 static int32 child_main(void * data)
787 int child_num_arg = (int) data;
791 int my_child_num = child_num_arg;
792 proc_info *my_info = NULL;
799 ap_create_context(&pchild, pconf);
801 /*stuff to do before we switch id's, so we have permissions.*/
802 SAFE_ACCEPT(intra_mutex_init(pchild, 1));
803 SAFE_ACCEPT(accept_mutex_child_init(pchild));
805 if (beosd_setup_child()) {
806 clean_child_exit(APEXIT_CHILDFATAL);
809 ap_child_init_hook(pchild, server_conf);
811 /*done with init critical section */
813 /* All threads should mask signals out, accoring to sigwait(2) man page */
814 sigfillset(&sig_mask);
815 sigprocmask(SIG_BLOCK, &sig_mask, NULL);
817 requests_this_child = ap_max_requests_per_child;
819 /* Set up the pollfd array */
820 listenfds = ap_palloc(pchild, sizeof(struct pollfd) * (num_listenfds));
821 for (lr = ap_listeners, i = 0; i < num_listenfds; lr = lr->next, ++i) {
822 ap_get_os_sock(&listenfds[i].fd , lr->sd);
823 listenfds[i].events = POLLIN; /* should we add POLLPRI ?*/
824 listenfds[i].revents = 0;
827 /* Setup worker threads */
829 worker_thread_count = 0;
830 be_mutex_init(&worker_thread_count_mutex, NULL);
832 for (i=0; i < ap_threads_per_child; i++) {
834 my_info = (proc_info *)malloc(sizeof(proc_info));
835 if (my_info == NULL) {
836 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, server_conf,
837 "malloc: out of memory");
838 clean_child_exit(APEXIT_CHILDFATAL);
840 my_info->pid = my_child_num;
843 ap_create_context(&my_info->tpool, pchild);
845 /* We are creating threads right now */
847 if ((thread = spawn_thread(worker_thread, "httpd_worker_thread",
848 B_NORMAL_PRIORITY, my_info)) < B_NO_ERROR) {
849 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, server_conf,
850 "spawn_thread: unable to create worker thread");
851 /* In case system resources are maxxed out, we don't want
852 Apache running away with the CPU trying to fork over and
853 over and over again if we exit. */
855 clean_child_exit(APEXIT_CHILDFATAL);
857 resume_thread(thread);
859 /* We let each thread update it's own scoreboard entry. This is done
860 * because it let's us deal with tid better.
864 sigemptyset(&sa.sa_mask);
866 sa.sa_handler = just_die;
867 sigaction(SIGTERM, &sa, NULL);
868 sigaction(SIGINT, &sa, NULL);
869 /* this blocks until it gets a message... */
870 read_port(port_of_death, &msg, &buf, 1);
875 static int make_child(server_rec *s, int slot, time_t now)
879 if (slot + 1 > max_daemons_limit) {
880 max_daemons_limit = slot + 1;
885 child_table[slot].pid = getpid();
886 child_table[slot].status = SERVER_ALIVE;
890 tid = spawn_thread(child_main, "httpd_child", B_NORMAL_PRIORITY,
892 if (tid < B_NO_ERROR) {
893 ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
894 "spawn_thread: Unable to fork new process");
895 /* In case system resources are maxxed out, we don't want
896 Apache running away with the CPU trying to fork over and
897 over and over again. */
904 child_table[slot].pid = getpid();
905 child_table[slot].status = SERVER_ALIVE;
909 /* start up a bunch of children */
910 static void startup_children(int number_to_start)
914 for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
915 if (child_table[i].status != SERVER_DEAD) {
918 if (make_child(server_conf, i, 0) < 0) {
927 * spawn_rate is the number of children that will be spawned on the
928 * next maintenance cycle if there aren't enough idle servers. It is
929 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
930 * without the need to spawn.
932 static int spawn_rate = 1;
933 #ifndef MAX_SPAWN_RATE
934 #define MAX_SPAWN_RATE (32)
936 static int hold_off_on_exponential_spawning;
938 static void perform_idle_server_maintenance(void)
941 int idle_thread_count;
944 int free_slots[MAX_SPAWN_RATE];
948 /* initialize the free_list */
953 for (i = 0; i < ap_daemons_limit; ++i) {
954 if (child_table[i].status == SERVER_DEAD) {
955 if (free_length < spawn_rate) {
956 free_slots[free_length] = i;
964 if (i >= max_daemons_limit && free_length >= spawn_rate) {
968 max_daemons_limit = last_non_dead + 1;
970 if (free_length > 0) {
971 for (i = 0; i < free_length; ++i) {
972 make_child(server_conf, free_slots[i], now);
974 /* the next time around we want to spawn twice as many if this
975 * wasn't good enough, but not if we've just done a graceful
977 if (hold_off_on_exponential_spawning) {
978 --hold_off_on_exponential_spawning;
979 } else if (spawn_rate < MAX_SPAWN_RATE) {
987 static void server_main_loop(int remaining_children_to_start)
994 while (!restart_pending && !shutdown_pending) {
995 pid = wait_or_timeout(&status);
998 process_child_status(pid, status);
999 /* non-fatal death... note that it's gone in the scoreboard. */
1001 for (i = 0; i < max_daemons_limit; ++i) {
1002 if (child_table[i].pid == pid) {
1006 for (j = 0; j < HARD_THREAD_LIMIT; j++) {
1007 ap_mpmt_beos_force_reset_connection_status(i * HARD_THREAD_LIMIT + j);
1012 if (child_slot >= 0) {
1013 child_table[child_slot].status = SERVER_DEAD;
1015 if (remaining_children_to_start
1016 && child_slot < ap_daemons_limit) {
1017 /* we're still doing a 1-for-1 replacement of dead
1018 * children with new children
1020 make_child(server_conf, child_slot, time(NULL));
1021 --remaining_children_to_start;
1023 #ifdef HAS_OTHER_CHILD
1025 else if (reap_other_child(pid, status) == 0) {
1029 else if (is_graceful) {
1030 /* Great, we've probably just lost a slot in the
1031 * scoreboard. Somehow we don't know about this
1034 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, server_conf,
1035 "long lost child came home! (pid %d)", pid);
1037 /* Don't perform idle maintenance when a child dies,
1038 * only do it when there's a timeout. Remember only a
1039 * finite number of children can die, and it's pretty
1040 * pathological for a lot to die suddenly.
1044 else if (remaining_children_to_start) {
1045 /* we hit a 1 second timeout in which none of the previous
1046 * generation of children needed to be reaped... so assume
1047 * they're all done, and pick up the slack if any is left.
1049 startup_children(remaining_children_to_start);
1050 remaining_children_to_start = 0;
1051 /* In any event we really shouldn't do the code below because
1052 * few of the servers we just started are in the IDLE state
1053 * yet, so we'd mistakenly create an extra server.
1058 perform_idle_server_maintenance();
1062 int ap_mpm_run(ap_context_t *_pconf, ap_context_t *plog, server_rec *s)
1064 int remaining_children_to_start;
1068 port_of_death = create_port(1, "httpd_port_of_death");
1070 if ((num_listenfds = setup_listeners(server_conf)) < 1) {
1071 /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
1072 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, errno, s,
1073 "no listening sockets available, shutting down");
1076 ap_log_pid(pconf, ap_pid_fname);
1077 SAFE_ACCEPT(accept_mutex_init(pconf, 1));
1079 reinit_scoreboard(pconf);
1083 /* Don't thrash... */
1084 if (max_spare_threads < min_spare_threads + ap_threads_per_child)
1085 max_spare_threads = min_spare_threads + ap_threads_per_child;
1087 /* If we're doing a graceful_restart then we're going to see a lot
1088 * of children exiting immediately when we get into the main loop
1089 * below (because we just sent them SIGWINCH). This happens pretty
1090 * rapidly... and for each one that exits we'll start a new one until
1091 * we reach at least daemons_min_free. But we may be permitted to
1092 * start more than that, so we'll just keep track of how many we're
1093 * supposed to start up without the 1 second penalty between each fork.
1095 remaining_children_to_start = ap_daemons_to_start;
1096 if (remaining_children_to_start > ap_daemons_limit) {
1097 remaining_children_to_start = ap_daemons_limit;
1100 startup_children(remaining_children_to_start);
1101 remaining_children_to_start = 0;
1104 /* give the system some time to recover before kicking into
1105 * exponential mode */
1106 hold_off_on_exponential_spawning = 10;
1109 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, server_conf,
1110 "%s configured -- resuming normal operations",
1111 ap_get_server_version());
1112 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, errno, server_conf,
1113 "Server built: %s", ap_get_server_built());
1114 restart_pending = shutdown_pending = 0;
1116 server_main_loop(remaining_children_to_start);
1118 if (shutdown_pending) {
1119 /* Time to gracefully shut down:
1120 * Kill child processes, tell them to call child_exit, etc...
1122 if (ap_killpg(getpgrp(), SIGTERM) < 0) {
1123 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf,
1126 reclaim_child_processes(1); /* Start with SIGTERM */
1128 /* cleanup pid file on normal shutdown */
1130 const char *pidfile = NULL;
1131 pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1132 if ( pidfile != NULL && unlink(pidfile) == 0)
1133 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
1135 "removed PID file %s (pid=%ld)",
1136 pidfile, (long)getpid());
1139 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, server_conf,
1140 "caught SIGTERM, shutting down");
1145 /* we've been told to restart */
1146 signal(SIGHUP, SIG_IGN);
1149 /* not worth thinking about */
1155 char char_of_death = '!';
1157 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, server_conf,
1158 "SIGWINCH received. Doing graceful restart");
1160 /* give the children the signal to die */
1161 for (i = 0; i < ap_daemons_limit;) {
1162 if(child_table[i].status != SERVER_DEAD) {
1163 if (write_port(port_of_death, 99, &char_of_death, 1) != B_OK) {
1164 if (errno == EINTR) continue;
1165 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf,
1166 "write port_of_death");
1174 /* Kill 'em all. Since the child acts the same on the parents SIGTERM
1175 * and a SIGHUP, we may as well use the same signal, because some user
1176 * pthreads are stealing signals from us left and right.
1178 if (ap_killpg(getpgrp(), SIGTERM) < 0) {
1179 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, server_conf,
1182 reclaim_child_processes(1); /* Start with SIGTERM */
1183 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, server_conf,
1184 "SIGHUP received. Attempting to restart");
1187 ap_restart_time = time(NULL);
1189 delete_port(port_of_death);
1193 static void mpmt_beos_pre_config(ap_context_t *pconf, ap_context_t *plog, ap_context_t *ptemp)
1195 static int restart_num = 0;
1197 one_process = !!getenv("ONE_PROCESS");
1199 /* sigh, want this only the second time around */
1200 if (restart_num++ == 1) {
1211 ap_listen_pre_config();
1212 ap_daemons_to_start = DEFAULT_START_DAEMON;
1213 min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
1214 max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
1215 ap_daemons_limit = HARD_SERVER_LIMIT;
1216 ap_threads_per_child = DEFAULT_THREADS_PER_CHILD;
1217 ap_pid_fname = DEFAULT_PIDLOG;
1218 ap_scoreboard_fname = DEFAULT_SCOREBOARD;
1219 ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
1220 ap_mpmt_beos_set_maintain_connection_status(1);
1222 ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1225 static void mpmt_beos_hooks(void)
1227 ap_hook_pre_config(mpmt_beos_pre_config,NULL,NULL,HOOK_MIDDLE);
1233 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg)
1235 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1240 if (cmd->server->is_virtual) {
1241 return "PidFile directive not allowed in <VirtualHost>";
1247 static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg)
1249 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1254 ap_scoreboard_fname = arg;
1258 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg)
1260 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1265 ap_daemons_to_start = atoi(arg);
1269 static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, char *arg)
1271 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1276 min_spare_threads = atoi(arg);
1277 if (min_spare_threads <= 0) {
1278 fprintf(stderr, "WARNING: detected MinSpareThreads set to non-positive.\n");
1279 fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
1280 fprintf(stderr, "Please read the documentation.\n");
1281 min_spare_threads = 1;
1287 static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, char *arg)
1289 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1294 max_spare_threads = atoi(arg);
1298 static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg)
1300 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1305 ap_daemons_limit = atoi(arg);
1306 if (ap_daemons_limit > HARD_SERVER_LIMIT) {
1307 fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
1308 "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
1309 fprintf(stderr, " lowering MaxClients to %d. To increase, please "
1310 "see the\n", HARD_SERVER_LIMIT);
1311 fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
1312 ap_daemons_limit = HARD_SERVER_LIMIT;
1314 else if (ap_daemons_limit < 1) {
1315 fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
1316 ap_daemons_limit = 1;
1321 static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg)
1323 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1328 ap_threads_per_child = atoi(arg);
1329 if (ap_threads_per_child > HARD_THREAD_LIMIT) {
1330 fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time"
1331 "limit of %d threads,\n", ap_threads_per_child,
1333 fprintf(stderr, " lowering ThreadsPerChild to %d. To increase, please"
1334 "see the\n", HARD_THREAD_LIMIT);
1335 fprintf(stderr, " HARD_THREAD_LIMIT define in src/include/httpd.h.\n");
1337 else if (ap_threads_per_child < 1) {
1338 fprintf(stderr, "WARNING: Require ThreadsPerChild > 0, setting to 1\n");
1339 ap_threads_per_child = 1;
1344 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg)
1346 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1351 ap_max_requests_per_child = atoi(arg);
1356 static const char *set_maintain_connection_status(cmd_parms *cmd,
1357 core_dir_config *d, int arg)
1359 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1364 ap_mpmt_beos_set_maintain_connection_status(arg != 0);
1368 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg)
1372 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1377 fname = ap_server_root_relative(cmd->pool, arg);
1378 if ((stat(fname, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
1379 return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
1380 " does not exist or is not a directory", NULL);
1382 ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
1386 struct ap_thread_mutex {
1390 API_EXPORT(ap_thread_mutex *) ap_thread_mutex_new(void)
1392 ap_thread_mutex *mtx;
1394 mtx = malloc(sizeof(ap_thread_mutex));
1395 be_mutex_init(&(mtx->mutex), NULL);
1399 API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
1401 /* Ignoring error conditions here. :( */
1402 be_mutex_lock(&(mtx->mutex));
1405 API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
1408 be_mutex_unlock(&(mtx->mutex));
1411 API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
1414 be_mutex_destroy(&(mtx->mutex));
1419 static const command_rec mpmt_beos_cmds[] = {
1420 UNIX_DAEMON_COMMANDS
1422 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
1423 "A file for logging the server process ID"},
1424 { "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
1425 "A file for Apache to maintain runtime process management information"},
1426 { "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
1427 "Number of child processes launched at server startup" },
1428 { "MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, TAKE1,
1429 "Minimum number of idle children, to handle request spikes" },
1430 { "MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, TAKE1,
1431 "Maximum number of idle children" },
1432 { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
1433 "Maximum number of children alive at the same time" },
1434 { "ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, TAKE1,
1435 "Number of threads each child creates" },
1436 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
1437 "Maximum number of requests a particular child serves before dying." },
1438 { "ConnectionStatus", set_maintain_connection_status, NULL, RSRC_CONF, FLAG,
1439 "Whether or not to maintain status information on current connections"},
1440 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
1441 "The location of the directory Apache changes to before dumping core" },
1445 module MODULE_VAR_EXPORT mpm_mpmt_beos_module = {
1446 STANDARD20_MODULE_STUFF,
1447 NULL, /* create per-directory config structure */
1448 NULL, /* merge per-directory config structures */
1449 NULL, /* create per-server config structure */
1450 NULL, /* merge per-server config structures */
1451 mpmt_beos_cmds, /* command ap_table_t */
1452 NULL, /* handlers */
1453 mpmt_beos_hooks /* register_hooks */