From: David Reid Date: Tue, 20 Jun 2000 14:30:01 +0000 (+0000) Subject: The new beos mpm. This is the first pass but will let more X-Git-Tag: APACHE_2_0_ALPHA_5~288 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eb3c5ca7aab0a8daa37109ac4ffa91c127a72ccb;p=apache The new beos mpm. This is the first pass but will let more people test later this week. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@85629 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/server/mpm/beos/Makefile.in b/server/mpm/beos/Makefile.in new file mode 100644 index 0000000000..ba75075533 --- /dev/null +++ b/server/mpm/beos/Makefile.in @@ -0,0 +1,5 @@ + +LTLIBRARY_NAME = libbeos.la +LTLIBRARY_SOURCES = beos.c scoreboard.c + +include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/beos/beos.c b/server/mpm/beos/beos.c new file mode 100644 index 0000000000..b70576bb16 --- /dev/null +++ b/server/mpm/beos/beos.c @@ -0,0 +1,1134 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +/* The new BeOS MPM! + * + * This one basically is a single process multi threaded model, but + * I couldn't be bothered adding the spmt_ to the front of the name! + * Anyway, this is still under development so it isn't yet the default + * choice. + */ + +#define CORE_PRIVATE + +#include "apr_portable.h" +#include "httpd.h" +#include "http_main.h" +#include "http_log.h" +#include "http_config.h" /* for read_config */ +#include "http_core.h" /* for get_remote_host */ +#include "http_connection.h" +#include "ap_mpm.h" +#include "beosd.h" +#include "iol_socket.h" +#include "ap_listen.h" +#include "scoreboard.h" +//#include "poll.h" +#include "mpm_common.h" +#include "mpm.h" +#include +#include + +/* + * Actual definitions of config globals + */ + +int ap_threads_per_child=0; /* Worker threads per child */ +int ap_max_requests_per_child=0; +static char *ap_pid_fname=NULL; +static char *ap_scoreboard_fname=NULL; +static int ap_threads_to_start=0; +static int min_spare_threads=0; +static int max_spare_threads=0; +static int ap_thread_limit=0; +static time_t ap_restart_time=0; +API_VAR_EXPORT int ap_extended_status = 0; +static int num_listening_sockets = 0; /* set by open_listeners in ap_mpm_run */ +static ap_socket_t ** listening_sockets; +ap_lock_t *accept_mutex = NULL; + +static ap_pool_t *pconf; /* Pool for config stuff */ +static ap_pool_t *pchild; /* Pool for httpd child stuff */ + +static int server_pid; + +/* Keep track of the number of worker threads currently active */ +static int worker_thread_count; +ap_lock_t *worker_thread_count_mutex; + +/* The structure used to pass unique initialization info to each thread */ +typedef struct { + int slot; + ap_pool_t *tpool; +} proc_info; + +struct ap_ctable ap_child_table[HARD_SERVER_LIMIT]; + +/* + * The max child slot ever assigned, preserved across restarts. Necessary + * to deal with MaxClients changes across SIGWINCH restarts. We use this + * value to optimize routines that have to scan the entire scoreboard. + */ +int ap_max_child_assigned = -1; +int ap_max_threads_limit = -1; +static char ap_coredump_dir[MAX_STRING_LEN]; + +/* shared http_main globals... */ + +server_rec *ap_server_conf; + +/* one_process */ +/* TODO - get this working again... */ +static int one_process = 0; + +#ifdef DEBUG_SIGSTOP +int raise_sigstop_flags; +#endif + +API_EXPORT(const server_rec *) ap_get_server_conf(void) +{ + return (ap_server_conf); +} + +API_EXPORT(int) ap_get_max_daemons(void) +{ + return ap_max_child_assigned; +} + +/* a clean exit from a child with proper cleanup + static void clean_child_exit(int code) __attribute__ ((noreturn)); */ +void clean_child_exit(int code) +{ + if (pchild) + ap_destroy_pool(pchild); + exit(code); +} + +/* handle all varieties of core dumping signals */ +static void sig_coredump(int sig) +{ + chdir(ap_coredump_dir); + signal(sig, SIG_DFL); + kill(server_pid, sig); + /* At this point we've got sig blocked, because we're still inside + * the signal handler. When we leave the signal handler it will + * be unblocked, and we'll take the signal... and coredump or whatever + * is appropriate for this particular Unix. In addition the parent + * will see the real signal we received -- whereas if we called + * abort() here, the parent would only see SIGABRT. + */ +} + +/***************************************************************** + * Connection structures and accounting... + */ + +/* volatile just in case */ +static int volatile shutdown_pending; +static int volatile restart_pending; +static int volatile is_graceful; + +/* + * ap_start_shutdown() and ap_start_restart(), below, are a first stab at + * functions to initiate shutdown or restart without relying on signals. + * Previously this was initiated in sig_term() and restart() signal handlers, + * but we want to be able to start a shutdown/restart from other sources -- + * e.g. on Win32, from the service manager. Now the service manager can + * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that + * these functions can also be called by the child processes, since global + * variables are no longer used to pass on the required action to the parent. + * + * These should only be called from the parent process itself, since the + * parent process will use the shutdown_pending and restart_pending variables + * to determine whether to shutdown or restart. The child process should + * call signal_parent() directly to tell the parent to die -- this will + * cause neither of those variable to be set, which the parent will + * assume means something serious is wrong (which it will be, for the + * child to force an exit) and so do an exit anyway. + */ + +void ap_start_shutdown(void) +{ + if (shutdown_pending == 1) { + /* Um, is this _probably_ not an error, if the user has + * tried to do a shutdown twice quickly, so we won't + * worry about reporting it. + */ + return; + } + shutdown_pending = 1; +} + +/* do a graceful restart if graceful == 1 */ +void ap_start_restart(int graceful) +{ + + if (restart_pending == 1) { + /* Probably not an error - don't bother reporting it */ + return; + } + restart_pending = 1; + is_graceful = graceful; +} + +static void sig_term(int sig) +{ + ap_start_shutdown(); +} + +static void restart(int sig) +{ + ap_start_restart(sig == SIGWINCH); +} + +static void tell_workers_to_exit() +{ + int i, code = 99; + + for (i=0;i= NumSIG) ? "" : + SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status), + ap_coredump_dir); + } + else { +#endif + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, + errno, ap_server_conf, + "child pid %d exit signal %s (%d)", pid, + SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status)); +#ifdef WCOREDUMP + } +#endif +#else + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, + errno, ap_server_conf, + "child pid %d exit signal %d", + pid, WTERMSIG(status)); +#endif + } + } +} + +static int setup_listeners(server_rec *s) +{ + ap_listen_rec *lr; + int num_listeners = 0; + if (ap_listen_open(s->process, s->port)) { + return 0; + } + for (lr = ap_listeners; lr; lr = lr->next) { + num_listeners++; + } + return num_listeners; +} + +/***************************************************************** + * Here follows a long bunch of generic server bookkeeping stuff... + */ + +//#define sock_disable_nagle(s) /* NOOP */ + +int ap_graceful_stop_signalled(void) +{ + /* XXX - Does this really work? - Manoj */ + return is_graceful; +} + +/***************************************************************** + * Child process main loop. + */ + +static void process_socket(ap_pool_t *p, ap_socket_t *sock, int my_child_num) +{ + BUFF *conn_io; + conn_rec *current_conn; + ap_iol *iol; + long conn_id = my_child_num; + int csd; + + iol = beos_attach_socket(sock); + if (iol == NULL) { + if (errno == EBADF) { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, NULL, + "filedescriptor (%u) larger than FD_SETSIZE (%u) " + "found, you probably need to rebuild Apache with a " + "larger FD_SETSIZE", csd, FD_SETSIZE); + } + else { + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, NULL, + "error attaching to socket"); + } + ap_close_socket(sock); + return; + } + + conn_io = ap_bcreate(p, B_RDWR); + ap_bpush_iol(conn_io, iol); + + current_conn = ap_new_apr_connection(p, ap_server_conf, conn_io, sock, + conn_id); + + ap_process_connection(current_conn); + ap_lingering_close(current_conn); +} + +static int32 worker_thread(void * dummy) +{ + proc_info * ti = dummy; + int child_slot = ti->slot; + ap_pool_t *tpool = ti->tpool; + ap_socket_t *csd = NULL; + ap_pool_t *ptrans; /* Pool for per-transaction stuff */ + ap_socket_t *sd = NULL; + int srv , n; + int curr_pollfd, last_pollfd = 0; + sigset_t sig_mask; + int requests_this_child = ap_max_requests_per_child; + ap_pollfd_t *pollset; + /* each worker thread is in control of it's own destiny...*/ + int this_worker_should_exit = 0; + thread_id me = find_thread(NULL); + + free(ti); + + /* block the signals for this thread */ + sigfillset(&sig_mask); + sigprocmask(SIG_BLOCK, &sig_mask, NULL); + + ap_create_pool(&ptrans, tpool); + + ap_lock(worker_thread_count_mutex); + worker_thread_count++; + ap_unlock(worker_thread_count_mutex); + + /* now setup our own pollset...this will use APR woohoo! */ + ap_setup_poll(&pollset, num_listening_sockets, tpool); + for(n=0 ; n < num_listening_sockets ; ++n) + ap_add_poll_socket(pollset, listening_sockets[n], APR_POLLIN); + + while (!this_worker_should_exit) { + this_worker_should_exit |= (ap_max_requests_per_child != 0) && (requests_this_child <= 0); + + if (this_worker_should_exit) break; + + ap_lock(accept_mutex); + while (!this_worker_should_exit) { + ap_int16_t event; + ap_status_t ret = ap_poll(pollset, &srv, -1); + + if (has_data(me)) { + thread_id sender; + receive_data(&sender, NULL, 0); + this_worker_should_exit = 1; + } + if (ret != APR_SUCCESS) { + if (errno == EINTR) { + continue; + } + + /* poll() will only return errors in catastrophic + * circumstances. Let's try exiting gracefully, for now. */ + ap_log_error(APLOG_MARK, APLOG_ERR,errno, (const server_rec *) + ap_get_server_conf(), "poll: (listen)"); + this_worker_should_exit = 1; + } + + if (this_worker_should_exit) break; + + if (num_listening_sockets == 1) { + sd = ap_listeners->sd; + goto got_fd; + } + else { + /* find a listener */ + curr_pollfd = last_pollfd; + do { + curr_pollfd++; + if (curr_pollfd > num_listening_sockets) { + curr_pollfd = 1; + } + /* Get the revent... */ + ap_get_revents(&event, listening_sockets[curr_pollfd], pollset); + + /* XXX: Should we check for POLLERR? */ + if (event & APR_POLLIN) { + last_pollfd = curr_pollfd; + sd = listening_sockets[curr_pollfd]; + goto got_fd; + } + } while (curr_pollfd != last_pollfd); + } + } + got_fd: + if (!this_worker_should_exit) { + ap_accept(&csd, sd, ptrans); + ap_unlock(accept_mutex); + process_socket(ptrans, csd, child_slot); + requests_this_child--; + } + else { + ap_unlock(accept_mutex); + break; + } + ap_clear_pool(ptrans); + } + + ap_destroy_pool(tpool); + ap_lock(worker_thread_count_mutex); + worker_thread_count--; + if (worker_thread_count == 0) { + /* All the threads have exited, now finish the shutdown process + * by signalling the sigwait thread */ + kill(server_pid, SIGTERM); + } + ap_unlock(worker_thread_count_mutex); + + return (0); +} + +static int make_worker(server_rec *s, int slot, time_t now) +{ + thread_id tid; + proc_info *my_info = (proc_info *)malloc(sizeof(proc_info)); + + if (my_info == NULL) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, + "malloc: out of memory"); + clean_child_exit(APEXIT_CHILDFATAL); + } + + my_info->slot = slot; + ap_create_pool(&my_info->tpool, pchild); + + if (slot + 1 > ap_max_child_assigned) + ap_max_child_assigned = slot + 1; + + /* TODO: figure out the one_process stuff... */ +/* + if (one_process) { + set_signals(); + ap_child_table[slot].pid = getpid(); + ap_child_table[slot].status = SERVER_ALIVE; + } +This is deliberate to remind me to do something about it! +*/ + + tid = spawn_thread(worker_thread, "apache_worker", B_NORMAL_PRIORITY, + my_info); + if (tid < B_NO_ERROR) { + ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, + "spawn_thread: Unable to start a new thread"); + /* In case system resources are maxxed out, we don't want + * Apache running away with the CPU trying to fork over and + * over and over again. */ + sleep(10); + + return -1; + } + resume_thread(tid); + + ap_child_table[slot].pid = getpid(); + ap_child_table[slot].status = SERVER_ALIVE; + return 0; +} + +/* start up a bunch of children */ +static void startup_threads(int number_to_start) +{ + int i; + + for (i = 0; number_to_start && i < ap_thread_limit; ++i) { + if (ap_child_table[i].status != SERVER_DEAD) { + continue; + } + if (make_worker(ap_server_conf, i, 0) < 0) { + break; + } + --number_to_start; + } +} + + +/* + * spawn_rate is the number of children that will be spawned on the + * next maintenance cycle if there aren't enough idle servers. It is + * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by + * without the need to spawn. + */ +static int spawn_rate = 1; +#ifndef MAX_SPAWN_RATE +#define MAX_SPAWN_RATE (32) +#endif +static int hold_off_on_exponential_spawning; + +static void perform_idle_server_maintenance(void) +{ + int i; + time_t now = 0; + int free_length; + int free_slots[MAX_SPAWN_RATE]; + int last_non_dead; + + /* initialize the free_list */ + free_length = 0; + + for (i = 0; i < ap_thread_limit; ++i) { + if (ap_child_table[i].status == SERVER_DEAD) { + if (free_length < spawn_rate) { + free_slots[free_length] = i; + ++free_length; + } + } + else { + last_non_dead = i; + } + + if (i >= ap_max_child_assigned && free_length >= spawn_rate) { + break; + } + } + ap_max_child_assigned = last_non_dead + 1; + + if (free_length > 0) { + for (i = 0; i < free_length; ++i) { + make_worker(ap_server_conf, free_slots[i], now); + } + /* the next time around we want to spawn twice as many if this + * wasn't good enough, but not if we've just done a graceful + */ + if (hold_off_on_exponential_spawning) { + --hold_off_on_exponential_spawning; + } else if (spawn_rate < MAX_SPAWN_RATE) { + spawn_rate *= 2; + } + } else { + spawn_rate = 1; + } +} + +static void server_main_loop(int remaining_threads_to_start) +{ + int child_slot; + ap_wait_t status; + ap_proc_t pid; + int i; + + while (!restart_pending && !shutdown_pending) { + ap_wait_or_timeout(&status, &pid, pconf); + + if (pid.pid >= 0) { + process_child_status(pid.pid, status); + /* non-fatal death... note that it's gone in the scoreboard. */ + child_slot = -1; + for (i = 0; i < ap_max_child_assigned; ++i) { + if (ap_child_table[i].pid == pid.pid) { + int j; + + child_slot = i; + for (j = 0; j < HARD_THREAD_LIMIT; j++) { + ap_beos_force_reset_connection_status(i * HARD_THREAD_LIMIT + j); + } + break; + } + } + if (child_slot >= 0) { + ap_child_table[child_slot].status = SERVER_DEAD; + + if (remaining_threads_to_start + && child_slot < ap_thread_limit) { + /* we're still doing a 1-for-1 replacement of dead + * children with new children + */ + make_worker(ap_server_conf, child_slot, time(NULL)); + --remaining_threads_to_start; + } +#ifdef APR_HAS_OTHER_CHILD + } + else if (ap_reap_other_child(&pid, status) == 0) { + /* handled */ +#endif + } + else if (is_graceful) { + /* Great, we've probably just lost a slot in the + * scoreboard. Somehow we don't know about this + * child. + */ + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, ap_server_conf, + "long lost child came home! (pid %ld)", pid.pid); + } + + /* Don't perform idle maintenance when a child dies, + * only do it when there's a timeout. Remember only a + * finite number of children can die, and it's pretty + * pathological for a lot to die suddenly. + */ + continue; + } + else if (remaining_threads_to_start) { + /* we hit a 1 second timeout in which none of the previous + * generation of children needed to be reaped... so assume + * they're all done, and pick up the slack if any is left. + */ + startup_threads(remaining_threads_to_start); + remaining_threads_to_start = 0; + /* In any event we really shouldn't do the code below because + * few of the servers we just started are in the IDLE state + * yet, so we'd mistakenly create an extra server. + */ + continue; + } + + perform_idle_server_maintenance(); + } +} + +int ap_mpm_run(ap_pool_t *_pconf, ap_pool_t *plog, server_rec *s) +{ + int remaining_threads_to_start, i; + ap_status_t rv; + ap_listen_rec *lr; + pconf = _pconf; + ap_server_conf = s; + + if ((num_listening_sockets = setup_listeners(ap_server_conf)) < 1) { + /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */ + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, errno, s, + "no listening sockets available, shutting down"); + return 1; + } + + ap_log_pid(pconf, ap_pid_fname); + + /* + * Create our locks... + */ + + /* accept_mutex + * used to lock around select so we only have one thread + * in select at a time + */ + if ((rv = ap_create_lock(&accept_mutex, APR_MUTEX, APR_CROSS_PROCESS, + NULL, pconf)) != APR_SUCCESS) { + /* tsch tsch, can't have more than one thread in the accept loop + at a time so we need to fall on our sword... */ + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, + "Couldn't create accept lock"); + return 1; + } + /* worker_thread_count_mutex + * locks the worker_thread_count so we have ana ccurate count... + */ + if ((rv = ap_create_lock(&worker_thread_count_mutex, APR_MUTEX, APR_CROSS_PROCESS, + NULL, pconf)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, + "Couldn't create worker thread count lock"); + return 1; + } + + /* + * Startup/shutdown... + */ + + if (!is_graceful) + reinit_scoreboard(pconf); + + set_signals(); + /* Sanity cehcks to avoid thrashing... */ + if (max_spare_threads < min_spare_threads ) + max_spare_threads = min_spare_threads; + + /* If we're doing a graceful_restart then we're going to see a lot + * of threads exiting immediately when we get into the main loop + * below (because we just sent them SIGWINCH). This happens pretty + * rapidly... and for each one that exits we'll start a new one until + * we reach at least threads_min_free. But we may be permitted to + * start more than that, so we'll just keep track of how many we're + * supposed to start up without the 1 second penalty between each fork. + */ + remaining_threads_to_start = ap_threads_to_start; + /* sanity check on the number to start... */ + if (remaining_threads_to_start > ap_thread_limit) { + remaining_threads_to_start = ap_thread_limit; + } + + /* setup the child pool to use for the workers. Each worker creates + * a seperate pool of it's own to use. + */ + ap_create_pool(&pchild, pconf); + ap_child_init_hook(pchild, ap_server_conf); + + /* Now that we have the child pool (pchild) we can allocate + * the listenfds and creat the pollset... + */ + listening_sockets = ap_palloc(pchild, + sizeof(*listening_sockets) * (num_listening_sockets)); + for (lr = ap_listeners, i = 0; i < num_listening_sockets; lr = lr->next, ++i) + listening_sockets[i]=lr->sd; + + /* we assume all goes OK...hmm might want to check that! */ + if (!is_graceful) { + startup_threads(remaining_threads_to_start); + remaining_threads_to_start = 0; + } + else { + /* give the system some time to recover before kicking into + * exponential mode */ + hold_off_on_exponential_spawning = 10; + } + + /* + * record that we've entered the world ! + */ + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, ap_server_conf, + "%s configured -- resuming normal operations", + ap_get_server_version()); + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, errno, ap_server_conf, + "Server built: %s", ap_get_server_built()); + restart_pending = shutdown_pending = 0; + + /* + * main_loop until it's all over + */ + server_main_loop(remaining_threads_to_start); + + /* + * If we get here we're shutting down... + */ + if (shutdown_pending) { + /* Time to gracefully shut down: + * Kill child processes, tell them to call child_exit, etc... + */ + if (beosd_killpg(getpgrp(), SIGTERM) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, + "killpg SIGTERM"); + + /* cleanup pid file on normal shutdown */ + { + const char *pidfile = NULL; + pidfile = ap_server_root_relative (pconf, ap_pid_fname); + if ( pidfile != NULL && unlink(pidfile) == 0) + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, + errno, ap_server_conf, + "removed PID file %s (pid=%ld)", + pidfile, (long)getpid()); + } + + /* use ap_reclaim_child_processes starting with SIGTERM */ + ap_reclaim_child_processes(1); + + /* record the shutdown in the log */ + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, ap_server_conf, + "caught SIGTERM, shutting down"); + + return 1; + } + + /* we've been told to restart */ + signal(SIGHUP, SIG_IGN); + + if (one_process) { + return 1; + } + + if (is_graceful) { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, ap_server_conf, + "SIGWINCH received. Doing graceful restart"); + tell_workers_to_exit(); + /* TODO - need to test some ideas here... */ + } + else { + /* Kill 'em all. Since the child acts the same on the parents SIGTERM + * and a SIGHUP, we may as well use the same signal, because some user + * pthreads are stealing signals from us left and right. + */ + push_workers_off_cliff(SIGTERM); + + ap_reclaim_child_processes(1); /* Start with SIGTERM */ + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, errno, ap_server_conf, + "SIGHUP received. Attempting to restart"); + } + + if (!is_graceful) { + ap_restart_time = time(NULL); + } + + return 0; +} + +static void beos_pre_config(ap_pool_t *pconf, ap_pool_t *plog, ap_pool_t *ptemp) +{ + static int restart_num = 0; + + one_process = !!getenv("ONE_PROCESS"); + + /* sigh, want this only the second time around */ + if (restart_num++ == 1) { + is_graceful = 0; + if (!one_process) + beosd_detach(); + server_pid = getpid(); + } + + beosd_pre_config(); + ap_listen_pre_config(); + ap_threads_to_start = DEFAULT_START_THREADS; + min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; + max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; + ap_thread_limit = HARD_SERVER_LIMIT; + ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; + ap_pid_fname = DEFAULT_PIDLOG; + ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; + ap_beos_set_maintain_connection_status(1); + + ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); +} + +static void beos_hooks(void) +{ + INIT_SIGLIST() + one_process = 0; + + ap_hook_pre_config(beos_pre_config, NULL, NULL, AP_HOOK_MIDDLE); +} + + +static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + if (cmd->server->is_virtual) { + return "PidFile directive not allowed in "; + } + ap_pid_fname = arg; + return NULL; +} + +static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + ap_scoreboard_fname = arg; + return NULL; +} + +static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + ap_threads_to_start = atoi(arg); + return NULL; +} + +static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + min_spare_threads = atoi(arg); + if (min_spare_threads <= 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "WARNING: detected MinSpareThreads set to non-positive."); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "Resetting to 1 to avoid almost certain Apache failure."); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "Please read the documentation."); + min_spare_threads = 1; + } + + return NULL; +} + +static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + max_spare_threads = atoi(arg); + return NULL; +} + +static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + ap_thread_limit = atoi(arg); + if (ap_thread_limit > HARD_SERVER_LIMIT) { + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "WARNING: MaxClients of %d exceeds compile time limit " + "of %d servers,", ap_thread_limit, HARD_SERVER_LIMIT); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " lowering MaxClients to %d. To increase, please " + "see the", HARD_SERVER_LIMIT); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " HARD_SERVER_LIMIT define in src/include/httpd.h."); + ap_thread_limit = HARD_SERVER_LIMIT; + } + else if (ap_thread_limit < 1) { + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "WARNING: Require MaxClients > 0, setting to 1"); + ap_thread_limit = 1; + } + return NULL; +} + +static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + ap_threads_per_child = atoi(arg); + if (ap_threads_per_child > HARD_THREAD_LIMIT) { + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "WARNING: ThreadsPerChild of %d exceeds compile time" + "limit of %d threads,\n", ap_threads_per_child, + HARD_THREAD_LIMIT); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " lowering ThreadsPerChild to %d. To increase, please" + "see the", HARD_THREAD_LIMIT); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " HARD_THREAD_LIMIT define in src/include/httpd.h."); + } + else if (ap_threads_per_child < 1) { + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "WARNING: Require ThreadsPerChild > 0, setting to 1"); + ap_threads_per_child = 1; + } + return NULL; +} + +static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + ap_max_requests_per_child = atoi(arg); + + return NULL; +} + +static const char *set_maintain_connection_status(cmd_parms *cmd, + core_dir_config *d, int arg) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + ap_beos_set_maintain_connection_status(arg != 0); + return NULL; +} + +static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) +{ + ap_finfo_t finfo; + const char *fname; + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + fname = ap_server_root_relative(cmd->pool, arg); + if ((ap_stat(&finfo, fname, cmd->pool) != APR_SUCCESS) || + (finfo.filetype != APR_DIR)) { + return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, + " does not exist or is not a directory", NULL); + } + ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); + return NULL; +} + +static const command_rec beos_cmds[] = { +UNIX_DAEMON_COMMANDS +LISTEN_COMMANDS +{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1, + "A file for logging the server process ID"}, +{ "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1, + "A file for Apache to maintain runtime process management information"}, +{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, + "Number of child processes launched at server startup" }, +{ "MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, TAKE1, + "Minimum number of idle children, to handle request spikes" }, +{ "MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, TAKE1, + "Maximum number of idle children" }, +{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, + "Maximum number of children alive at the same time" }, +{ "ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, TAKE1, + "Number of threads each child creates" }, +{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, + "Maximum number of requests a particular child serves before dying." }, +{ "ConnectionStatus", set_maintain_connection_status, NULL, RSRC_CONF, FLAG, + "Whether or not to maintain status information on current connections"}, +{ "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1, + "The location of the directory Apache changes to before dumping core" }, +{ NULL } +}; + +module MODULE_VAR_EXPORT mpm_beos_module = { + MPM20_MODULE_STUFF, + NULL, /* hook to run before apache parses args */ + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + beos_cmds, /* command ap_table_t */ + NULL, /* handlers */ + beos_hooks /* register_hooks */ +}; + diff --git a/server/mpm/beos/beos.h b/server/mpm/beos/beos.h new file mode 100644 index 0000000000..c7cffdef24 --- /dev/null +++ b/server/mpm/beos/beos.h @@ -0,0 +1,69 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +#ifndef APACHE_MPM_BEOS_H +#define APACHE_MPM_BEOS_H + +extern int ap_threads_per_child; +extern int ap_max_requests_per_child; +extern int ap_pipe_of_death[2]; +extern int ap_extended_status; +extern void clean_child_exit(int); +extern int max_daemons_limit; + +#endif /* APACHE_MPM_BEOS_H */ diff --git a/server/mpm/beos/config.m4 b/server/mpm/beos/config.m4 new file mode 100644 index 0000000000..80def68ec4 --- /dev/null +++ b/server/mpm/beos/config.m4 @@ -0,0 +1,8 @@ +dnl ## XXX - Need a more thorough check of the proper flags to use + +if test "$MPM_NAME" = "beos" ; then + ac_cv_enable_threads="yes" + AC_CACHE_SAVE + + APACHE_FAST_OUTPUT(modules/mpm/$MPM_NAME/Makefile) +fi diff --git a/server/mpm/beos/mpm.h b/server/mpm/beos/mpm.h new file mode 100644 index 0000000000..af4e237777 --- /dev/null +++ b/server/mpm/beos/mpm.h @@ -0,0 +1,79 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +#ifndef APACHE_MPM_BEOS_H +#define APACHE_MPM_BEOS_H + +#define BEOS_MPM +extern int ap_max_child_assigned; +#include "scoreboard.h" + +#define SERVER_DEAD 0 +#define SERVER_DYING 1 +#define SERVER_ALIVE 2 + +typedef struct ap_ctable{ + pid_t pid; + unsigned char status; +} ap_ctable; + +extern ap_ctable ap_child_table[HARD_SERVER_LIMIT]; +extern server_rec *ap_server_conf; + + +#endif /* APACHE_MPM_BEOS_H */ diff --git a/server/mpm/beos/mpm_default.h b/server/mpm/beos/mpm_default.h new file mode 100644 index 0000000000..ffe055d40d --- /dev/null +++ b/server/mpm/beos/mpm_default.h @@ -0,0 +1,143 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +#ifndef APACHE_MPM_DEFAULT_H +#define APACHE_MPM_DEFAULT_H + +/* Number of servers to spawn off by default --- also, if fewer than + * this free when the caretaker checks, it will spawn more. + */ +#ifndef DEFAULT_START_DAEMON +#define DEFAULT_START_DAEMON 5 +#endif +#define DEFAULT_START_THREADS 20 + +/* Maximum number of *free* server processes --- more than this, and + * they will die off. + */ + +#ifndef DEFAULT_MAX_FREE_DAEMON +#define DEFAULT_MAX_FREE_DAEMON 10 +#endif + +/* Minimum --- fewer than this, and more will be created */ + +#ifndef DEFAULT_MIN_FREE_DAEMON +#define DEFAULT_MIN_FREE_DAEMON 5 +#endif + +/* Limit on the total --- clients will be locked out if more servers than + * this are needed. It is intended solely to keep the server from crashing + * when things get out of hand. + * + * We keep a hard maximum number of servers, for two reasons --- first off, + * in case something goes seriously wrong, we want to stop the fork bomb + * short of actually crashing the machine we're running on by filling some + * kernel table. Secondly, it keeps the size of the scoreboard file small + * enough that we can read the whole thing without worrying too much about + * the overhead. + */ + +#ifdef NO_THREADS +#define HARD_SERVER_LIMIT 256 +#endif +#ifndef HARD_SERVER_LIMIT +#define HARD_SERVER_LIMIT 64 +#endif + +/* Limit on the threads per process. Clients will be locked out if more than + * this * HARD_SERVER_LIMIT are needed. + * + * We keep this for one reason it keeps the size of the scoreboard file small + * enough that we can read the whole thing without worrying too much about + * the overhead. + */ +#ifdef NO_THREADS +#define HARD_THREAD_LIMIT 1 +#endif +#ifndef HARD_THREAD_LIMIT +#define HARD_THREAD_LIMIT 64 +#endif + +#ifdef NO_THREADS +#define DEFAULT_THREADS_PER_CHILD 1 +#endif +#ifndef DEFAULT_THREADS_PER_CHILD +#define DEFAULT_THREADS_PER_CHILD 10 +#endif + +/* Where the main/parent process's pid is logged */ +#ifndef DEFAULT_PIDLOG +#define DEFAULT_PIDLOG "logs/httpd.pid" +#endif + +/* + * Interval, in microseconds, between scoreboard maintenance. + */ +#ifndef SCOREBOARD_MAINTENANCE_INTERVAL +#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 +#endif + +/* Number of requests to try to handle in a single process. If <= 0, + * the children don't die off. + */ +#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD +#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 +#endif + +#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/beos/scoreboard.c b/server/mpm/beos/scoreboard.c new file mode 100644 index 0000000000..b85f79a722 --- /dev/null +++ b/server/mpm/beos/scoreboard.c @@ -0,0 +1,227 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +#include "httpd.h" +#include "http_log.h" +#include "http_main.h" +#include "http_core.h" +#include "http_config.h" +#include "mpm_status.h" +#include "mpm.h" /* includes scoreboard.h */ +#include "beosd.h" +#include "http_conf_globals.h" +#include "beos.h" + +scoreboard *ap_scoreboard_image = NULL; +extern ap_pool_t * pconf; +static int maintain_connection_status = 1; + +void reinit_scoreboard(ap_pool_t *p) +{ + ap_assert(!ap_scoreboard_image); + ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE); + if (ap_scoreboard_image == NULL) { + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + "Ouch! Out of memory reiniting scoreboard!"); + } + memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE); +} + +void cleanup_scoreboard(void) +{ + ap_assert(ap_scoreboard_image); + free(ap_scoreboard_image); + ap_scoreboard_image = NULL; +} + +API_EXPORT(int) ap_exists_scoreboard_image(void) +{ + return (ap_scoreboard_image ? 1 : 0); +} + + +void ap_update_connection_status(long conn_id, const char *key, + const char *value) +{ + int i = 0; + status_table_entry *ss; + + if (!maintain_connection_status) return; + while (i < STATUSES_PER_CONNECTION) { + ss = &(ap_scoreboard_image->table[conn_id][i]); + if (ss->key[0] == '\0') { + break; + } + if (0 == strcmp(ss->key, key)) { + ap_cpystrn(ss->value, value, VALUE_LENGTH); + return; + } + i++; + } + if (i >= STATUSES_PER_CONNECTION) { + return; + } + ap_cpystrn(ss->key, key, KEY_LENGTH); + ap_cpystrn(ss->value, value, VALUE_LENGTH); + return; +} + +void ap_reset_connection_status(long conn_id) +{ + if (maintain_connection_status) { + ap_beos_force_reset_connection_status(conn_id); + } +} + +void ap_beos_set_maintain_connection_status(int flag) { + maintain_connection_status = flag; + return; +} + +void ap_beos_force_reset_connection_status(long conn_id) +{ + int i; + + for (i = 0; i < STATUSES_PER_CONNECTION; i++) { + ap_scoreboard_image->table[conn_id][i].key[0] = '\0'; + } +} + +const char *ap_get_connection_status(long conn_id, const char *key) +{ + int i = 0; + status_table_entry *ss; + + if (!maintain_connection_status) return ""; + while (i < STATUSES_PER_CONNECTION) { + ss = &(ap_scoreboard_image->table[conn_id][i]); + if (ss->key[0] == '\0') { + break; + } + if (0 == strcmp(ss->key, key)) { + return ss->value; + } + } + + return NULL; +} + +ap_array_header_t *ap_get_connections(ap_pool_t *p) +{ + int i; + ap_array_header_t *connection_list; + long *array_slot; + + connection_list = ap_make_array(p, 0, sizeof(long)); + for (i = 0; i < ap_max_child_assigned; i++) { + if (ap_scoreboard_image->table[i][0].key[0] != '\0') { + array_slot = ap_push_array(connection_list); + *array_slot = i; + } + } + return connection_list; +} + +ap_array_header_t *ap_get_connection_keys(ap_pool_t *p, long conn_id) +{ + int i = 0; + status_table_entry *ss; + ap_array_header_t *key_list; + char **array_slot; + + key_list = ap_make_array(p, 0, KEY_LENGTH * sizeof(char)); + while (i < STATUSES_PER_CONNECTION) { + ss = &(ap_scoreboard_image->table[conn_id][i]); + if (ss->key[0] == '\0') { + break; + } + array_slot = ap_push_array(key_list); + *array_slot = ap_pstrdup(p, ss->key); + i++; + } + return key_list; +} + +ap_array_header_t *ap_get_status_table(ap_pool_t *p) +{ + int i, j; + ap_array_header_t *server_status; + ap_status_table_row_t *array_slot; + status_table_entry *ss; + + server_status = ap_make_array(p, 0, sizeof(ap_status_table_row_t)); + + for (i = 0; i < ap_max_child_assigned; i++) { + if (ap_scoreboard_image->table[i][0].key[0] == '\0') + continue; + array_slot = ap_push_array(server_status); + array_slot->data = ap_make_table(p, 0); + array_slot->conn_id = i; + + for (j = 0; j < STATUSES_PER_CONNECTION; j++) { + ss = &(ap_scoreboard_image->table[i][j]); + if (ss->key[0] != '\0') { + ap_table_add(array_slot->data, ss->key, ss->value); + } + else { + break; + } + } + } + return server_status; +} diff --git a/server/mpm/beos/scoreboard.h b/server/mpm/beos/scoreboard.h new file mode 100644 index 0000000000..8ca6d67860 --- /dev/null +++ b/server/mpm/beos/scoreboard.h @@ -0,0 +1,103 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +#ifndef BEOS_SCOREBOARD_H +#define BEOS_SCOREBOARD_H +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#include "mpm_default.h" /* For HARD_.*_LIMIT */ + +API_EXPORT(int) ap_exists_scoreboard_image(void); +void reinit_scoareboard(ap_pool_t *p); +void cleanup_scoreboard(void); +void ap_beos_set_maintain_connection_status(int flag); +void ap_beos_force_reset_connection_status(long conn_id); +void reinit_scoreboard(ap_pool_t *p); +void update_scoreboard_global(void); +API_EXPORT(int) find_child_by_pid(int pid); +int ap_update_child_status(int child_num, int thread_num, int status, request_rec *r); +void ap_time_process_request(int child_num, int thread_num, int status); + +/* Add support for connection table functions */ + +#define KEY_LENGTH 16 +#define VALUE_LENGTH 64 + +typedef struct { + char key[KEY_LENGTH]; + char value[VALUE_LENGTH]; +} status_table_entry; + +#define STATUSES_PER_CONNECTION 10 + +typedef struct { + status_table_entry + table[HARD_THREAD_LIMIT][STATUSES_PER_CONNECTION]; +} scoreboard; + +#define SCOREBOARD_SIZE sizeof(scoreboard) + +#ifdef __cplusplus +} +#endif + +#endif /* !BEOS_SCOREBOARD_H */