diff options
author | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 03:10:21 -0500 |
---|---|---|
committer | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 03:10:21 -0500 |
commit | c0b7206652b2852bc574694e7ba07ba1c2acdc00 (patch) | |
tree | 5cb95cb0e19e03610525903df46279df2c3b7eb1 /rubbos/app/httpd-2.0.64/server/mpm | |
parent | b6d3d6e668b793220f2d3af1bc3e828553dc3fe6 (diff) |
delete app
Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2
Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/httpd-2.0.64/server/mpm')
79 files changed, 0 insertions, 20865 deletions
diff --git a/rubbos/app/httpd-2.0.64/server/mpm/.deps b/rubbos/app/httpd-2.0.64/server/mpm/.deps deleted file mode 100644 index e69de29b..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/.deps +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/MPM.NAMING b/rubbos/app/httpd-2.0.64/server/mpm/MPM.NAMING deleted file mode 100644 index 83c0694d..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/MPM.NAMING +++ /dev/null @@ -1,15 +0,0 @@ - -The following MPMs currently exist: - - prefork ....... Multi Process Model with Preforking (Apache 1.3) - perchild ...... Multi Process Model with Threading. - Constant number of processes, variable number of threads - each child process can have a different uid/gid. - mpmt_os2 ...... Multi Process Model with Threading on OS/2 - Constant number of processes, variable number of threads. - One acceptor thread per process, multiple workers threads. - winnt ......... Single Process Model with Threading on Windows NT - worker ........ Multi Process model with threads. One acceptor thread, - multiple worker threads. - netware ....... Multi-threaded MPM for Netware - beos .......... Single Process Model with Threading on BeOS diff --git a/rubbos/app/httpd-2.0.64/server/mpm/Makefile b/rubbos/app/httpd-2.0.64/server/mpm/Makefile deleted file mode 100644 index b1f2ed46..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -top_srcdir = /bottlenecks/rubbos/app/httpd-2.0.64 -top_builddir = /bottlenecks/rubbos/app/httpd-2.0.64 -srcdir = /bottlenecks/rubbos/app/httpd-2.0.64/server/mpm -builddir = /bottlenecks/rubbos/app/httpd-2.0.64/server/mpm -VPATH = /bottlenecks/rubbos/app/httpd-2.0.64/server/mpm - -SUBDIRS = $(MPM_SUBDIR_NAME) - -include $(top_builddir)/build/rules.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/Makefile.in deleted file mode 100644 index 2decbde6..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/Makefile.in +++ /dev/null @@ -1,4 +0,0 @@ - -SUBDIRS = $(MPM_SUBDIR_NAME) - -include $(top_builddir)/build/rules.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/beos/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/beos/Makefile.in deleted file mode 100644 index 3f88b041..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/beos/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libbeos.la -LTLIBRARY_SOURCES = beos.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/beos/beos.c b/rubbos/app/httpd-2.0.64/server/mpm/beos/beos.c deleted file mode 100644 index 51a17c3e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/beos/beos.c +++ /dev/null @@ -1,1159 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* 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 <kernel/OS.h> -#include <unistd.h> -#include <sys/socket.h> -#include <signal.h> - -#include "apr_strings.h" -#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 "ap_listen.h" -#include "scoreboard.h" -#include "mpm_common.h" -#include "mpm.h" -#include "mpm_default.h" -#include "apr_thread_mutex.h" -#include "apr_poll.h" - -extern int _kset_fd_limit_(int num); - -/* 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: - * 1) in case something goes seriously wrong, we want to stop the server starting - * threads ad infinitum and crashing the server (remember that BeOS has a 192 - * thread per team limit). - * 2) it keeps the size of the scoreboard file small - * enough that we can read the whole thing without worrying too much about - * the overhead. - */ - -/* we only ever have 1 main process running... */ -#define HARD_SERVER_LIMIT 1 - -/* 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 50 -#endif - -/* - * Actual definitions of config globals - */ - -static int ap_threads_to_start=0; -static int ap_max_requests_per_thread = 0; -static int min_spare_threads=0; -static int max_spare_threads=0; -static int ap_thread_limit=0; -static int num_listening_sockets = 0; -static apr_socket_t ** listening_sockets; -apr_thread_mutex_t *accept_mutex = NULL; - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static int server_pid; -static int mpm_state = AP_MPMQ_STARTING; - -/* Keep track of the number of worker threads currently active */ -static int worker_thread_count; -apr_thread_mutex_t *worker_thread_count_mutex; - -/* The structure used to pass unique initialization info to each thread */ -typedef struct { - int slot; - apr_pool_t *tpool; -} proc_info; - -static void check_restart(void *data); - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across AP_SIG_GRACEFUL 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 apr_socket_t *udp_sock; -static apr_sockaddr_t *udp_sa; - -/* shared http_main globals... */ - -server_rec *ap_server_conf; - -/* one_process */ -static int one_process = 0; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -/* a clean exit from a child with proper cleanup - static void clean_child_exit(int code) __attribute__ ((noreturn)); */ -static void clean_child_exit(int code) -{ - if (pchild) - apr_pool_destroy(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; -static int volatile child_fatal; -ap_generation_t volatile ap_my_generation = 0; - -/* - * 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. - */ - -static void ap_start_shutdown(void) -{ - mpm_state = AP_MPMQ_STOPPING; - - 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 */ -static void ap_start_restart(int graceful) -{ - mpm_state = AP_MPMQ_STOPPING; - - 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 == AP_SIG_GRACEFUL); -} - -static void tell_workers_to_exit(void) -{ - apr_size_t len; - int i = 0; - - mpm_state = AP_MPMQ_STOPPING; - - for (i = 0 ; i < ap_max_child_assigned; i++){ - len = 4; - if (apr_sendto(udp_sock, udp_sa, 0, "die!", &len) != APR_SUCCESS) - break; - } -} - -static void set_signals(void) -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - if (!one_process) { - sa.sa_handler = sig_coredump; - - if (sigaction(SIGSEGV, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)"); - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)"); - sa.sa_flags = 0; - } - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)"); - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)"); - - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)"); - - /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy - * processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")"); -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) -{ - /* XXX - Does this really work? - Manoj */ - return is_graceful; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, - int my_child_num, apr_bucket_alloc_t *bucket_alloc) -{ - conn_rec *current_conn; - long conn_id = my_child_num; - int csd; - ap_sb_handle_t *sbh; - - (void)apr_os_sock_get(&csd, sock); - - if (csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, - "filedescriptor (%u) larger than FD_SETSIZE (%u) " - "found, you probably need to rebuild Apache with a " - "larger FD_SETSIZE", csd, FD_SETSIZE); - apr_socket_close(sock); - return; - } - - ap_create_sb_handle(&sbh, p, 0, my_child_num); - current_conn = ap_run_create_connection(p, ap_server_conf, - sock, conn_id, sbh, - bucket_alloc); - - if (current_conn) { - ap_process_connection(current_conn, sock); - ap_lingering_close(current_conn); - } -} - -static int32 worker_thread(void * dummy) -{ - proc_info * ti = dummy; - int child_slot = ti->slot; - apr_pool_t *tpool = ti->tpool; - apr_allocator_t *allocator; - apr_socket_t *csd = NULL; - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_bucket_alloc_t *bucket_alloc; - apr_socket_t *sd = NULL; - apr_status_t rv = APR_EINIT; - int srv , n; - int curr_pollfd = 0, last_pollfd = 0; - sigset_t sig_mask; - int requests_this_child = ap_max_requests_per_thread; - apr_pollfd_t *pollset; - /* each worker thread is in control of its own destiny...*/ - int this_worker_should_exit = 0; - free(ti); - - mpm_state = AP_MPMQ_STARTING; - - on_exit_thread(check_restart, (void*)child_slot); - - /* block the signals for this thread */ - sigfillset(&sig_mask); - sigprocmask(SIG_BLOCK, &sig_mask, NULL); - - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - apr_pool_create_ex(&ptrans, tpool, NULL, allocator); - apr_allocator_owner_set(allocator, ptrans); - - apr_pool_tag(ptrans, "transaction"); - - bucket_alloc = apr_bucket_alloc_create_ex(allocator); - - apr_thread_mutex_lock(worker_thread_count_mutex); - worker_thread_count++; - apr_thread_mutex_unlock(worker_thread_count_mutex); - - (void) ap_update_child_status_from_indexes(0, child_slot, SERVER_STARTING, - (request_rec*)NULL); - - apr_poll_setup(&pollset, num_listening_sockets + 1, tpool); - for(n=0 ; n <= num_listening_sockets ; n++) - apr_poll_socket_add(pollset, listening_sockets[n], APR_POLLIN); - - mpm_state = AP_MPMQ_RUNNING; - - while (1) { - /* If we're here, then chances are (unless we're the first thread created) - * we're going to be held up in the accept mutex, so doing this here - * shouldn't hurt performance. - */ - - this_worker_should_exit |= (ap_max_requests_per_thread != 0) && (requests_this_child <= 0); - - if (this_worker_should_exit) break; - - (void) ap_update_child_status_from_indexes(0, child_slot, SERVER_READY, - (request_rec*)NULL); - - apr_thread_mutex_lock(accept_mutex); - - while (!this_worker_should_exit) { - apr_int16_t event; - apr_status_t ret; - - ret = apr_poll(pollset, num_listening_sockets + 1, &srv, -1); - - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - /* poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - this_worker_should_exit = 1; - } else { - /* if we've bailed in apr_poll what's the point of trying to use the data? */ - apr_poll_revents_get(&event, listening_sockets[0], pollset); - - if (event & APR_POLLIN){ - apr_sockaddr_t *rec_sa; - apr_size_t len = 5; - char *tmpbuf = apr_palloc(ptrans, sizeof(char) * 5); - apr_sockaddr_info_get(&rec_sa, "127.0.0.1", APR_UNSPEC, 7772, 0, ptrans); - - if ((ret = apr_recvfrom(rec_sa, listening_sockets[0], 0, tmpbuf, &len)) - != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, NULL, - "error getting data from UDP!!"); - }else { - /* add checking??? */ - } - 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... */ - apr_poll_revents_get(&event, listening_sockets[curr_pollfd], pollset); - - 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) { - rv = apr_accept(&csd, sd, ptrans); - - apr_thread_mutex_unlock(accept_mutex); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "apr_accept"); - } else { - process_socket(ptrans, csd, child_slot, bucket_alloc); - requests_this_child--; - } - } - else { - apr_thread_mutex_unlock(accept_mutex); - break; - } - apr_pool_clear(ptrans); - } - - ap_update_child_status_from_indexes(0, child_slot, SERVER_DEAD, (request_rec*)NULL); - - apr_bucket_alloc_destroy(bucket_alloc); - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, - "worker_thread %ld exiting", find_thread(NULL)); - - apr_thread_mutex_lock(worker_thread_count_mutex); - worker_thread_count--; - apr_thread_mutex_unlock(worker_thread_count_mutex); - - return (0); -} - -static int make_worker(int slot) -{ - thread_id tid; - proc_info *my_info = (proc_info *)malloc(sizeof(proc_info)); /* freed by thread... */ - - 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; - apr_pool_create(&my_info->tpool, pchild); - - if (slot + 1 > ap_max_child_assigned) - ap_max_child_assigned = slot + 1; - - if (one_process) { - set_signals(); - ap_scoreboard_image->parent[0].pid = getpid(); - return 0; - } - - (void) ap_update_child_status_from_indexes(0, slot, SERVER_STARTING, (request_rec*)NULL); - 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, NULL, - "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. - */ - (void) ap_update_child_status_from_indexes(0, slot, SERVER_DEAD, - (request_rec*)NULL); - - sleep(10); - free(my_info); - - return -1; - } - resume_thread(tid); - - ap_scoreboard_image->servers[0][slot].tid = tid; - return 0; -} - -static void check_restart(void *data) -{ - if (!restart_pending && !shutdown_pending) { - int slot = (int)data; - make_worker(slot); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, - "spawning a new worker thread in slot %d", slot); - } -} - -/* 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_scoreboard_image->servers[0][i].tid) { - continue; - } - if (make_worker(i) < 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; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead = -1; - - /* initialize the free_list */ - free_length = 0; - - for (i = 0; i < ap_thread_limit; ++i) { - if (ap_scoreboard_image->servers[0][i].tid == 0) { - 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(free_slots[i]); - } - /* 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; - apr_exit_why_e exitwhy; - int status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - - ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); - - if (pid.pid >= 0) { - if (ap_process_child_status(&pid, exitwhy, status) == APEXIT_CHILDFATAL) { - shutdown_pending = 1; - child_fatal = 1; - return; - } - /* 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_scoreboard_image->servers[0][i].tid == pid.pid) { - child_slot = i; - break; - } - } - if (child_slot >= 0) { - ap_scoreboard_image->servers[0][child_slot].tid = 0; - (void) ap_update_child_status_from_indexes(0, child_slot, - SERVER_DEAD, - (request_rec*)NULL); - - 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(child_slot); - --remaining_threads_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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_WARNING, 0, 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(); - } -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_max_child_assigned; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = max_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = min_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_thread; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_threads_to_start, i,j; - apr_status_t rv; - ap_listen_rec *lr; - pconf = _pconf; - ap_server_conf = s; - - /* Increase the available pool of fd's. This code from - * Joe Kloss <joek@be.com> - */ - if( FD_SETSIZE > 128 && (i = _kset_fd_limit_( 128 )) < 0 ){ - ap_log_error(APLOG_MARK, APLOG_ERR, i, s, - "could not set FD_SETSIZE (_kset_fd_limit_ failed)"); - } - - /* BeOS R5 doesn't support pipes on select() calls, so we use a - UDP socket as these are supported in both R5 and BONE. If we only cared - about BONE we'd use a pipe, but there it is. - As we have UDP support in APR, now use the APR functions and check all the - return values... - */ - if (apr_sockaddr_info_get(&udp_sa, "127.0.0.1", APR_UNSPEC, 7772, 0, _pconf) - != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, s, - "couldn't create control socket information, shutting down"); - return 1; - } - if (apr_socket_create(&udp_sock, udp_sa->family, SOCK_DGRAM, - _pconf) != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, s, - "couldn't create control socket, shutting down"); - return 1; - } - if (apr_bind(udp_sock, udp_sa) != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, s, - "couldn't bind UDP socket!"); - return 1; - } - - if ((num_listening_sockets = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, 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 - */ - rv = apr_thread_mutex_create(&accept_mutex, 0, pconf); - if (rv != 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... - */ - rv = apr_thread_mutex_create(&worker_thread_count_mutex, 0, pconf); - if (rv != 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) { - /* setup the scoreboard shared memory */ - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - return 1; - } - - for (i = 0; i < HARD_SERVER_LIMIT; i++) { - ap_scoreboard_image->parent[i].pid = 0; - for (j = 0;j < HARD_THREAD_LIMIT; j++) - ap_scoreboard_image->servers[i][j].tid = 0; - } - } - - if (HARD_SERVER_LIMIT == 1) - ap_scoreboard_image->parent[0].pid = getpid(); - - set_signals(); - - /* Sanity checks 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 AP_SIG_GRACEFUL). 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 its own to use. - */ - apr_pool_create(&pchild, pconf); - - /* Now that we have the child pool (pchild) we can allocate - * the listenfds and creat the pollset... - */ - listening_sockets = apr_palloc(pchild, - sizeof(*listening_sockets) * (num_listening_sockets + 1)); - - listening_sockets[0] = udp_sock; - for (lr = ap_listeners, i = 1; 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 we're in one_process mode we don't want to start threads - * do we?? - */ - if (!is_graceful && !one_process) { - 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_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - - restart_pending = shutdown_pending = 0; - - /* - * main_loop until it's all over - */ - if (!one_process) { - server_main_loop(remaining_threads_to_start); - - tell_workers_to_exit(); /* if we get here we're exiting... */ - sleep(1); /* give them a brief chance to exit */ - } else { - proc_info *my_info = (proc_info *)malloc(sizeof(proc_info)); - my_info->slot = 0; - apr_pool_create(&my_info->tpool, pchild); - worker_thread(my_info); - } - - /* close the UDP socket we've been using... */ - apr_socket_close(listening_sockets[0]); - - if ((one_process || shutdown_pending) && !child_fatal) { - 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_INFO, 0, ap_server_conf, - "removed PID file %s (pid=%ld)", pidfile, - (long)getpid()); - } - - if (one_process) { - return 1; - } - - /* - * 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"); - - /* use ap_reclaim_child_processes starting with SIGTERM */ - ap_reclaim_child_processes(1); - - if (!child_fatal) { /* already recorded */ - /* record the shutdown in the log */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - } - - return 1; - } - - /* we've been told to restart */ - signal(SIGHUP, SIG_IGN); - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); - } - 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. - */ - - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - /* just before we go, tidy up the locks we've created to prevent a - * potential leak of semaphores... */ - apr_thread_mutex_destroy(worker_thread_count_mutex); - apr_thread_mutex_destroy(accept_mutex); - - return 0; -} - -static int beos_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach, debug, foreground; - apr_status_t rv; - - mpm_state = AP_MPMQ_STARTING; - - debug = ap_exists_config_define("DEBUG"); - - if (debug) { - foreground = one_process = 1; - no_detach = 0; - } - else - { - one_process = ap_exists_config_define("ONE_PROCESS"); - no_detach = ap_exists_config_define("NO_DETACH"); - foreground = ap_exists_config_define("FOREGROUND"); - } - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !foreground) { - rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND - : APR_PROC_DETACH_DAEMONIZE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "apr_proc_detach failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - - server_pid = getpid(); - } - - beosd_pre_config(); - ap_listen_pre_config(); - ap_threads_to_start = DEFAULT_START_THREADS; - min_spare_threads = DEFAULT_MIN_FREE_THREADS; - max_spare_threads = DEFAULT_MAX_FREE_THREADS; - ap_thread_limit = HARD_THREAD_LIMIT; - ap_pid_fname = DEFAULT_PIDLOG; - ap_max_requests_per_thread = DEFAULT_MAX_REQUESTS_PER_THREAD; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static void beos_hooks(apr_pool_t *p) -{ - one_process = 0; - - ap_hook_pre_config(beos_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); -} - -static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_to_start = atoi(arg); - if (ap_threads_to_start < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "StartThreads set to a value less than 0, reset to 1"); - ap_threads_to_start = 1; - } - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, const 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, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, const 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_threads_limit (cmd_parms *cmd, void *dummy, const 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_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,", ap_thread_limit, HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " HARD_THREAD_LIMIT define in server/mpm/beos/mpm_default.h."); - ap_thread_limit = HARD_THREAD_LIMIT; - } - else if (ap_thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to %d", HARD_THREAD_LIMIT); - ap_thread_limit = HARD_THREAD_LIMIT; - } - return NULL; -} - -static const char *set_max_requests_per_thread (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_max_requests_per_thread = atoi(arg); - if (ap_max_requests_per_thread < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxRequestsPerThread was set below 0" - "reset to 0, but this may not be what you want."); - ap_max_requests_per_thread = 0; - } - - return NULL; -} - -static const command_rec beos_cmds[] = { -BEOS_DAEMON_COMMANDS, -LISTEN_COMMANDS, -AP_INIT_TAKE1( "StartThreads", set_threads_to_start, NULL, RSRC_CONF, - "Number of threads to launch at server startup"), -AP_INIT_TAKE1( "MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1( "MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle children" ), -AP_INIT_TAKE1( "MaxClients", set_threads_limit, NULL, RSRC_CONF, - "Maximum number of children alive at the same time (max threads)" ), -AP_INIT_TAKE1( "MaxRequestsPerThread", set_max_requests_per_thread, NULL, RSRC_CONF, - "Maximum number of requests served by a thread" ), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA 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 apr_table_t */ - beos_hooks /* register_hooks */ -}; - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/beos/beos.h b/rubbos/app/httpd-2.0.64/server/mpm/beos/beos.h deleted file mode 100644 index eb8a5509..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/beos/beos.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_BEOS_H -#define APACHE_MPM_BEOS_H - -extern int ap_threads_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/rubbos/app/httpd-2.0.64/server/mpm/beos/config5.m4 b/rubbos/app/httpd-2.0.64/server/mpm/beos/config5.m4 deleted file mode 100644 index 4f201408..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/beos/config5.m4 +++ /dev/null @@ -1,7 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "beos" ; then - apache_apr_flags="--enable-threads" - - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/beos/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/beos/mpm.h deleted file mode 100644 index 57221b1c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/beos/mpm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_BEOS_H -#define APACHE_MPM_BEOS_H - -#define BEOS_MPM -#include "scoreboard.h" - -#define MPM_NAME "Beos" -#define MPM_CHILD_PID(i) (ap_scoreboard_image->servers[0][i].tid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT -#define AP_MPM_WANT_PROCESS_CHILD_STATUS -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_MAX_MEM_FREE - -extern int ap_max_child_assigned; -extern server_rec *ap_server_conf; -extern int ap_threads_per_child; - -#endif /* APACHE_MPM_BEOS_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/beos/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/beos/mpm_default.h deleted file mode 100644 index 7bd0ce48..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/beos/mpm_default.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* we use the child (c) as zero in our code... */ -#define AP_ID_FROM_CHILD_THREAD(c, t) t -/* as the child is always zero, just return the id... */ -#define AP_CHILD_THREAD_FROM_ID(i) 0 , i - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREADS -#define DEFAULT_START_THREADS 10 -#endif - -#ifdef NO_THREADS -#define DEFAULT_THREADS 1 -#endif -#ifndef DEFAULT_THREADS -#define DEFAULT_THREADS 10 -#endif - -/* The following 2 settings are used to control the number of threads - * we have available. Normally the DEFAULT_MAX_FREE_THREADS is set - * to the same as the HARD_THREAD_LIMIT to avoid churning of starting - * new threads to replace threads killed off... - */ - -/* Maximum number of *free* threads --- more than this, and - * they will die off. - */ -#ifndef DEFAULT_MAX_FREE_THREADS -#define DEFAULT_MAX_FREE_THREADS HARD_THREAD_LIMIT -#endif - -/* Minimum --- fewer than this, and more will be created */ -#ifndef DEFAULT_MIN_FREE_THREADS -#define DEFAULT_MIN_FREE_THREADS 1 -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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_THREAD -#define DEFAULT_MAX_REQUESTS_PER_THREAD 0 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/config.m4 b/rubbos/app/httpd-2.0.64/server/mpm/config.m4 deleted file mode 100644 index c86a624e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/config.m4 +++ /dev/null @@ -1,45 +0,0 @@ -AC_MSG_CHECKING(which MPM to use) -AC_ARG_WITH(mpm, -APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use. - MPM={beos|worker|prefork|mpmt_os2|perchild|leader|threadpool}),[ - APACHE_MPM=$withval -],[ - if test "x$APACHE_MPM" = "x"; then - APACHE_MPM=prefork - fi -]) -AC_MSG_RESULT($APACHE_MPM) - -apache_cv_mpm=$APACHE_MPM - -if test "$apache_cv_mpm" = "worker" -o "$apache_cv_mpm" = "perchild" -o "$apache_cv_mpm" = "leader" -o "$apache_cv_mpm" = "threadpool" ; then - APR_CHECK_APR_DEFINE(APR_HAS_THREADS) - - if test "x$ac_cv_define_APR_HAS_THREADS" = "xno"; then - AC_MSG_RESULT(The currently selected MPM requires threads which your system seems to lack) - AC_MSG_CHECKING(checking for replacement) - AC_MSG_RESULT(prefork selected) - apache_cv_mpm=prefork - fi -fi - -APACHE_FAST_OUTPUT(server/mpm/Makefile) - -MPM_NAME=$apache_cv_mpm -if test "$MPM_NAME" = "leader" -o "$MPM_NAME" = "threadpool" -o "$MPM_NAME" = "perchild"; then - AC_MSG_WARN(You have selected an EXPERIMENTAL MPM. Be warned!) - MPM_SUBDIR_NAME=experimental/$MPM_NAME -else - MPM_SUBDIR_NAME=$MPM_NAME -fi -MPM_DIR=server/mpm/$MPM_SUBDIR_NAME -MPM_LIB=$MPM_DIR/lib${MPM_NAME}.la - -if test ! -f "$abs_srcdir/$MPM_DIR/mpm.h"; then - AC_MSG_ERROR(the selected mpm -- $apache_cv_mpm -- is not supported) -fi - -APACHE_SUBST(MPM_NAME) -APACHE_SUBST(MPM_SUBDIR_NAME) -MODLIST="$MODLIST mpm_${MPM_NAME}" - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/Makefile.in deleted file mode 100644 index 03f1765e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libleader.la -LTLIBRARY_SOURCES = leader.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/README b/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/README deleted file mode 100644 index 1981a5be..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/README +++ /dev/null @@ -1,15 +0,0 @@ -Leader MPM: -This is an experimental variant of the standard worker MPM. -It uses a Leader/Followers design pattern to coordinate work among threads: -http://deuce.doc.wustl.edu/doc/pspdfs/lf.pdf - -To use the leader MPM, add "--with-mpm=leader" to the configure -script's arguments when building the httpd. - -This MPM depends on APR's atomic compare-and-swap operations for -thread synchronization. If you are compiling for an x86 target -and you don't need to support 386s, or you're compiling for a -SPARC and you don't need to run on pre-UltraSPARC chips, add -"--enable-nonportable-atomics=yes" to the configure script's -arguments. This will cause APR to implement atomic operations -using efficient opcodes not available in older CPUs. diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/config5.m4 b/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/config5.m4 deleted file mode 100644 index 9a915abf..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/config5.m4 +++ /dev/null @@ -1,6 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "leader" ; then - AC_CHECK_FUNCS(pthread_kill) - APACHE_FAST_OUTPUT(server/mpm/$MPM_SUBDIR_NAME/Makefile) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/leader.c b/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/leader.c deleted file mode 100644 index 322c2286..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/leader.c +++ /dev/null @@ -1,1976 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" -#include "apr_thread_cond.h" -#include "apr_thread_mutex.h" -#include "apr_proc_mutex.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if APR_HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifdef HAVE_SYS_PROCESSOR_H -#include <sys/processor.h> /* for bindprocessor() */ -#endif - -#if !APR_HAS_THREADS -#error The Leader/Follower MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.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 "mpm_common.h" -#include "ap_listen.h" -#include "scoreboard.h" -#include "mpm_default.h" -#include "apr_poll.h" - -#include <signal.h> -#include <limits.h> /* for INT_MAX */ - -#include "apr_atomic.h" - -/* 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. - */ -#ifndef DEFAULT_SERVER_LIMIT -#define DEFAULT_SERVER_LIMIT 16 -#endif - -/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_SERVER_LIMIT -#define MAX_SERVER_LIMIT 20000 -#endif - -/* Limit on the threads per process. Clients will be locked out if more than - * this * 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. - */ -#ifndef DEFAULT_THREAD_LIMIT -#define DEFAULT_THREAD_LIMIT 64 -#endif - -/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_THREAD_LIMIT -#define MAX_THREAD_LIMIT 20000 -#endif - -/* - * Actual definitions of config globals - */ - -int ap_threads_per_child = 0; /* Worker threads per child */ -static int ap_daemons_to_start = 0; -static int min_spare_threads = 0; -static int max_spare_threads = 0; -static int ap_daemons_limit = 0; -static int server_limit = DEFAULT_SERVER_LIMIT; -static int first_server_limit; -static int thread_limit = DEFAULT_THREAD_LIMIT; -static int first_thread_limit; -static int changed_limit_at_restart; -static int dying = 0; -static int workers_may_exit = 0; -static int start_thread_may_exit = 0; -static int requests_this_child; -static int num_listensocks = 0; -static int resource_shortage = 0; -static int mpm_state = AP_MPMQ_STARTING; - -typedef struct worker_wakeup_info worker_wakeup_info; - -/* The structure used to pass unique initialization info to each thread */ -typedef struct { - int pid; - int tid; - int sd; -} proc_info; - - -/* Structure used to pass information to the thread responsible for - * creating the rest of the threads. - */ -typedef struct { - apr_thread_t **threads; - int child_num_arg; - apr_threadattr_t *threadattr; -} thread_starter; - -#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t) - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We - * use this value to optimize routines that have to scan the entire - * scoreboard. - */ -int ap_max_daemons_limit = -1; - -static ap_pod_t *pod; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* This MPM respects a couple of runtime flags that can aid in debugging. - * Setting the -DNO_DETACH flag will prevent the root process from - * detaching from its controlling terminal. Additionally, setting - * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the - * child_main loop running in the process which originally started up. - * This gives you a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -static int one_process = 0; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main - thread. Use this instead */ -static pid_t parent_pid; - -/* Locks for accept serialization */ -static apr_proc_mutex_t *accept_mutex; - -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS) -#else -#define SAFE_ACCEPT(stmt) (stmt) -#endif - - -/* Structure used to wake up an idle worker thread - */ -struct worker_wakeup_info { - apr_uint32_t next; /* index into worker_wakeups array, - * used to build a linked list - */ - apr_thread_cond_t *cond; - apr_thread_mutex_t *mutex; -}; - -static worker_wakeup_info *worker_wakeup_create(apr_pool_t *pool) -{ - apr_status_t rv; - worker_wakeup_info *wakeup; - - wakeup = (worker_wakeup_info *)apr_palloc(pool, sizeof(*wakeup)); - if ((rv = apr_thread_cond_create(&wakeup->cond, pool)) != APR_SUCCESS) { - return NULL; - } - if ((rv = apr_thread_mutex_create(&wakeup->mutex, APR_THREAD_MUTEX_DEFAULT, - pool)) != APR_SUCCESS) { - return NULL; - } - /* The wakeup's mutex will be unlocked automatically when - * the worker blocks on the condition variable - */ - apr_thread_mutex_lock(wakeup->mutex); - return wakeup; -} - - -/* Structure used to hold a stack of idle worker threads - */ -typedef struct { - /* 'state' consists of several fields concatenated into a - * single 32-bit int for use with the apr_atomic_cas() API: - * state & STACK_FIRST is the thread ID of the first thread - * in a linked list of idle threads - * state & STACK_TERMINATED indicates whether the proc is shutting down - * state & STACK_NO_LISTENER indicates whether the process has - * no current listener thread - */ - apr_uint32_t state; -} worker_stack; - -#define STACK_FIRST 0xffff -#define STACK_LIST_END 0xffff -#define STACK_TERMINATED 0x10000 -#define STACK_NO_LISTENER 0x20000 - -static worker_wakeup_info **worker_wakeups = NULL; - -static worker_stack* worker_stack_create(apr_pool_t *pool, apr_size_t max) -{ - worker_stack *stack = (worker_stack *)apr_palloc(pool, sizeof(*stack)); - stack->state = STACK_NO_LISTENER | STACK_LIST_END; - return stack; -} - -static apr_status_t worker_stack_wait(worker_stack *stack, - apr_uint32_t worker_id) -{ - worker_wakeup_info *wakeup = worker_wakeups[worker_id]; - - while (1) { - apr_uint32_t state = stack->state; - if (state & (STACK_TERMINATED | STACK_NO_LISTENER)) { - if (state & STACK_TERMINATED) { - return APR_EINVAL; - } - if (apr_atomic_cas(&(stack->state), STACK_LIST_END, state) != - state) { - continue; - } - else { - return APR_SUCCESS; - } - } - wakeup->next = state; - if (apr_atomic_cas(&(stack->state), worker_id, state) != state) { - continue; - } - else { - return apr_thread_cond_wait(wakeup->cond, wakeup->mutex); - } - } -} - -static apr_status_t worker_stack_awaken_next(worker_stack *stack) -{ - - while (1) { - apr_uint32_t state = stack->state; - apr_uint32_t first = state & STACK_FIRST; - if (first == STACK_LIST_END) { - if (apr_atomic_cas(&(stack->state), state | STACK_NO_LISTENER, - state) != state) { - continue; - } - else { - return APR_SUCCESS; - } - } - else { - worker_wakeup_info *wakeup = worker_wakeups[first]; - if (apr_atomic_cas(&(stack->state), (state ^ first) | wakeup->next, - state) != state) { - continue; - } - else { - /* Acquire and release the idle worker's mutex to ensure - * that it's actually waiting on its condition variable - */ - apr_status_t rv; - if ((rv = apr_thread_mutex_lock(wakeup->mutex)) != - APR_SUCCESS) { - return rv; - } - if ((rv = apr_thread_mutex_unlock(wakeup->mutex)) != - APR_SUCCESS) { - return rv; - } - return apr_thread_cond_signal(wakeup->cond); - } - } - } -} - -static apr_status_t worker_stack_term(worker_stack *stack) -{ - int i; - apr_status_t rv; - - while (1) { - apr_uint32_t state = stack->state; - if (apr_atomic_cas(&(stack->state), state | STACK_TERMINATED, - state) == state) { - break; - } - } - for (i = 0; i < ap_threads_per_child; i++) { - if ((rv = worker_stack_awaken_next(stack)) != APR_SUCCESS) { - return rv; - } - } - return APR_SUCCESS; -} - -static worker_stack *idle_worker_stack; - -#define ST_INIT 0 -#define ST_GRACEFUL 1 -#define ST_UNGRACEFUL 2 - -static int terminate_mode = ST_INIT; - -static void signal_threads(int mode) -{ - if (terminate_mode == mode) { - return; - } - terminate_mode = mode; - mpm_state = AP_MPMQ_STOPPING; - workers_may_exit = 1; - - worker_stack_term(idle_worker_stack); -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = server_limit; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = thread_limit; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = min_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = max_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = ap_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) __attribute__ ((noreturn)); -static void clean_child_exit(int code) -{ - mpm_state = AP_MPMQ_STOPPING; - if (pchild) { - apr_pool_destroy(pchild); - } - ap_mpm_pod_close(pod); - exit(code); -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -static volatile int child_fatal; -ap_generation_t volatile ap_my_generation; - -/* - * 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. - */ - -static void ap_start_shutdown(void) -{ - mpm_state = AP_MPMQ_STOPPING; - 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 */ -static void ap_start_restart(int graceful) -{ - mpm_state = AP_MPMQ_STOPPING; - 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) -{ - if (ap_my_pid == parent_pid) { - ap_start_shutdown(); - } - else { - signal_threads(ST_GRACEFUL); - } -} - -static void restart(int sig) -{ - ap_start_restart(sig == AP_SIG_GRACEFUL); -} - -static void set_signals(void) -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; -#endif - - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } - -#ifndef NO_USE_SIGACTION - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGINT)"); -#endif -#ifdef SIGXCPU - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXCPU, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXCPU)"); -#endif -#ifdef SIGXFSZ - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXFSZ, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXFSZ)"); -#endif -#ifdef SIGPIPE - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy - * processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(" AP_SIG_GRACEFUL_STRING ")"); -#else - if (!one_process) { -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef AP_SIG_GRACEFUL - apr_signal(AP_SIG_GRACEFUL, restart); -#endif /* AP_SIG_GRACEFUL */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) - /* XXX this is really a bad confusing obsolete name - * maybe it should be ap_mpm_process_exiting? - */ -{ - return workers_may_exit; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, - int my_thread_num, apr_bucket_alloc_t *bucket_alloc) -{ - conn_rec *current_conn; - long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num); - int csd; - ap_sb_handle_t *sbh; - - ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num); - apr_os_sock_get(&csd, sock); - - current_conn = ap_run_create_connection(p, ap_server_conf, sock, - conn_id, sbh, bucket_alloc); - if (current_conn) { - ap_process_connection(current_conn, sock); - ap_lingering_close(current_conn); - } -} - -/* requests_this_child has gone to zero or below. See if the admin coded - "MaxRequestsPerChild 0", and keep going in that case. Doing it this way - simplifies the hot path in worker_thread */ -static void check_infinite_requests(void) -{ - if (ap_max_requests_per_child) { - signal_threads(ST_GRACEFUL); - } - else { - /* wow! if you're executing this code, you may have set a record. - * either this child process has served over 2 billion requests, or - * you're running a threaded 2.0 on a 16 bit machine. - * - * I'll buy pizza and beers at Apachecon for the first person to do - * the former without cheating (dorking with INT_MAX, or running with - * uncommitted performance patches, for example). - * - * for the latter case, you probably deserve a beer too. Greg Ames - */ - - requests_this_child = INT_MAX; /* keep going */ - } -} - -static void unblock_signal(int sig) -{ - sigset_t sig_mask; - - sigemptyset(&sig_mask); - sigaddset(&sig_mask, sig); -#if defined(SIGPROCMASK_SETS_THREAD_MASK) - sigprocmask(SIG_UNBLOCK, &sig_mask, NULL); -#else - pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL); -#endif -} - -static void *worker_thread(apr_thread_t *thd, void * dummy) -{ - proc_info * ti = dummy; - int process_slot = ti->pid; - int thread_slot = ti->tid; - apr_uint32_t my_worker_num = (apr_uint32_t)(ti->tid); - apr_pool_t *tpool = apr_thread_pool_get(thd); - void *csd = NULL; - apr_allocator_t *allocator; - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_bucket_alloc_t *bucket_alloc; - int n; - apr_pollfd_t *pollset; - apr_status_t rv; - ap_listen_rec *lr, *last_lr = ap_listeners; - int is_listener; - - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL); - - free(ti); - - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - /* XXX: why is ptrans's parent not tpool? --jcw 08/2003 */ - apr_pool_create_ex(&ptrans, NULL, NULL, allocator); - apr_allocator_owner_set(allocator, ptrans); - bucket_alloc = apr_bucket_alloc_create_ex(allocator); - - apr_poll_setup(&pollset, num_listensocks, tpool); - for(lr = ap_listeners ; lr != NULL ; lr = lr->next) - apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); - - /* TODO: Switch to a system where threads reuse the results from earlier - poll calls - manoj */ - is_listener = 0; - while (!workers_may_exit) { - - ap_update_child_status_from_indexes(process_slot, thread_slot, - SERVER_READY, NULL); - if (!is_listener) { - /* Wait until it's our turn to become the listener */ - if ((rv = worker_stack_wait(idle_worker_stack, my_worker_num)) != - APR_SUCCESS) { - if (rv != APR_EINVAL) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "worker_stack_wait failed. Shutting down"); - } - break; - } - if (workers_may_exit) { - break; - } - is_listener = 1; - } - - /* TODO: requests_this_child should be synchronized - aaron */ - if (requests_this_child <= 0) { - check_infinite_requests(); - } - if (workers_may_exit) break; - - if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (workers_may_exit) { - break; - } - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_lock failed. Attempting to shutdown " - "process gracefully."); - signal_threads(ST_GRACEFUL); - break; /* skip the lock release */ - } - - if (!ap_listeners->next) { - /* Only one listener, so skip the poll */ - lr = ap_listeners; - } - else { - while (!workers_may_exit) { - apr_status_t ret; - apr_int16_t event; - - ret = apr_poll(pollset, num_listensocks, &n, -1); - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - - /* apr_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - signal_threads(ST_GRACEFUL); - } - - if (workers_may_exit) break; - - /* find a listener */ - lr = last_lr; - do { - lr = lr->next; - if (lr == NULL) { - lr = ap_listeners; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, lr->sd, pollset); - if (event & APR_POLLIN) { - last_lr = lr; - goto got_fd; - } - } while (lr != last_lr); - } - } - got_fd: - if (!workers_may_exit) { - rv = lr->accept_func(&csd, lr, ptrans); - /* later we trash rv and rely on csd to indicate success/failure */ - AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd); - - if (rv == APR_EGENERAL) { - /* E[NM]FILE, ENOMEM, etc */ - resource_shortage = 1; - signal_threads(ST_GRACEFUL); - } - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (workers_may_exit) { - break; - } - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - } - if (csd != NULL) { - is_listener = 0; - worker_stack_awaken_next(idle_worker_stack); - process_socket(ptrans, csd, process_slot, - thread_slot, bucket_alloc); - apr_pool_clear(ptrans); - requests_this_child--; - } - if ((ap_mpm_pod_check(pod) == APR_SUCCESS) || - (ap_my_generation != - ap_scoreboard_image->global->running_generation)) { - signal_threads(ST_GRACEFUL); - break; - } - } - else { - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - } - break; - } - } - - dying = 1; - ap_scoreboard_image->parent[process_slot].quiescing = 1; - - worker_stack_term(idle_worker_stack); - - ap_update_child_status_from_indexes(process_slot, thread_slot, - (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL); - - apr_bucket_alloc_destroy(bucket_alloc); - - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - return 1; - } - return 0; -} - -/* XXX under some circumstances not understood, children can get stuck - * in start_threads forever trying to take over slots which will - * never be cleaned up; for now there is an APLOG_DEBUG message issued - * every so often when this condition occurs - */ -static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) -{ - thread_starter *ts = dummy; - apr_thread_t **threads = ts->threads; - apr_threadattr_t *thread_attr = ts->threadattr; - int child_num_arg = ts->child_num_arg; - int my_child_num = child_num_arg; - proc_info *my_info; - apr_status_t rv; - int i; - int threads_created = 0; - int loops; - int prev_threads_created; - - idle_worker_stack = worker_stack_create(pchild, ap_threads_per_child); - if (idle_worker_stack == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, - "worker_stack_create() failed"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - worker_wakeups = (worker_wakeup_info **) - apr_palloc(pchild, sizeof(worker_wakeup_info *) * - ap_threads_per_child); - - loops = prev_threads_created = 0; - while (1) { - for (i = 0; i < ap_threads_per_child; i++) { - int status = ap_scoreboard_image->servers[child_num_arg][i].status; - worker_wakeup_info *wakeup; - - if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { - continue; - } - - wakeup = worker_wakeup_create(pchild); - if (wakeup == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, - ap_server_conf, "worker_wakeup_create failed"); - clean_child_exit(APEXIT_CHILDFATAL); - } - worker_wakeups[threads_created] = wakeup; - 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->pid = my_child_num; - my_info->tid = i; - my_info->sd = 0; - - /* We are creating threads right now */ - ap_update_child_status_from_indexes(my_child_num, i, - SERVER_STARTING, NULL); - /* We let each thread update its own scoreboard entry. This is - * done because it lets us deal with tid better. - */ - rv = apr_thread_create(&threads[i], thread_attr, - worker_thread, my_info, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker 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 if we exit. */ - apr_sleep(10 * APR_USEC_PER_SEC); - clean_child_exit(APEXIT_CHILDFATAL); - } - threads_created++; - } - if (start_thread_may_exit || threads_created == ap_threads_per_child) { - break; - } - /* wait for previous generation to clean up an entry */ - apr_sleep(1 * APR_USEC_PER_SEC); - ++loops; - if (loops % 120 == 0) { /* every couple of minutes */ - if (prev_threads_created == threads_created) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "child %" APR_PID_T_FMT " isn't taking over " - "slots very quickly (%d of %d)", - ap_my_pid, threads_created, ap_threads_per_child); - } - prev_threads_created = threads_created; - } - } - - /* What state should this child_main process be listed as in the - * scoreboard...? - * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, - * (request_rec *) NULL); - * - * This state should be listed separately in the scoreboard, in some kind - * of process_status, not mixed in with the worker threads' status. - * "life_status" is almost right, but it's in the worker's structure, and - * the name could be clearer. gla - */ - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -static void join_workers(apr_thread_t **threads) -{ - int i; - apr_status_t rv, thread_rv; - - for (i = 0; i < ap_threads_per_child; i++) { - if (threads[i]) { /* if we ever created this thread */ - rv = apr_thread_join(&thread_rv, threads[i]); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join worker " - "thread %d", - i); - } - } - } -} - -static void join_start_thread(apr_thread_t *start_thread_id) -{ - apr_status_t rv, thread_rv; - - start_thread_may_exit = 1; /* tell it to give up in case it is still - * trying to take over slots from a - * previous generation - */ - rv = apr_thread_join(&thread_rv, start_thread_id); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join the start " - "thread"); - } -} - -static void child_main(int child_num_arg) -{ - apr_thread_t **threads; - apr_status_t rv; - thread_starter *ts; - apr_threadattr_t *thread_attr; - apr_thread_t *start_thread_id; - - mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this - * child initializes - */ - - ap_my_pid = getpid(); - ap_fatal_signal_child_setup(ap_server_conf); - apr_pool_create(&pchild, pconf); - - /*stuff to do before we switch id's, so we have permissions.*/ - ap_reopen_scoreboard(pchild, NULL, 0); - - rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, - pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (unixd_setup_child()) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /* done with init critical section */ - - /* Just use the standard apr_setup_signal_thread to block all signals - * from being received. The child processes no longer use signals for - * any communication with the parent process. - */ - rv = apr_setup_signal_thread(); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize signal thread"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (ap_max_requests_per_child) { - requests_this_child = ap_max_requests_per_child; - } - else { - /* coding a value of zero means infinity */ - requests_this_child = INT_MAX; - } - - /* Setup worker threads */ - - /* clear the storage; we may not create all our threads immediately, - * and we want a 0 entry to indicate a thread which was not created - */ - threads = (apr_thread_t **)calloc(1, - sizeof(apr_thread_t *) * ap_threads_per_child); - if (threads == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, - "malloc: out of memory"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts)); - - apr_threadattr_create(&thread_attr, pchild); - /* 0 means PTHREAD_CREATE_JOINABLE */ - apr_threadattr_detach_set(thread_attr, 0); - - ts->threads = threads; - ts->child_num_arg = child_num_arg; - ts->threadattr = thread_attr; - - rv = apr_thread_create(&start_thread_id, thread_attr, start_threads, - ts, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker 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 if we exit. */ - apr_sleep(10 * APR_USEC_PER_SEC); - clean_child_exit(APEXIT_CHILDFATAL); - } - - mpm_state = AP_MPMQ_RUNNING; - - /* If we are only running in one_process mode, we will want to - * still handle signals. */ - if (one_process) { - /* Block until we get a terminating signal. */ - apr_signal_thread(check_signal); - /* make sure the start thread has finished; signal_threads() - * and join_workers() depend on that - */ - /* XXX join_start_thread() won't be awakened if one of our - * threads encounters a critical error and attempts to - * shutdown this child - */ - join_start_thread(start_thread_id); - signal_threads(ST_UNGRACEFUL); /* helps us terminate a little more - * quickly than the dispatch of the signal thread - * beats the Pipe of Death and the browsers - */ - /* A terminating signal was received. Now join each of the - * workers to clean them up. - * If the worker already exited, then the join frees - * their resources and returns. - * If the worker hasn't exited, then this blocks until - * they have (then cleans up). - */ - join_workers(threads); - } - else { /* !one_process */ - /* remove SIGTERM from the set of blocked signals... if one of - * the other threads in the process needs to take us down - * (e.g., for MaxRequestsPerChild) it will send us SIGTERM - */ - unblock_signal(SIGTERM); - join_start_thread(start_thread_id); - join_workers(threads); - } - - free(threads); - - clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_scoreboard_image->parent[slot].pid = getpid(); - child_main(slot); - } - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "fork: Unable to fork new process"); - - /* fork didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL); - - /* 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. */ - apr_sleep(10 * APR_USEC_PER_SEC); - - return -1; - } - - if (!pid) { -#ifdef HAVE_BINDPROCESSOR - /* By default, AIX binds to a single processor. This bit unbinds - * children which will then bind to another CPU. - */ - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, - ap_server_conf, - "processor unbind failed %d", status); -#endif - RAISE_SIGSTOP(MAKE_CHILD); - - apr_signal(SIGTERM, just_die); - child_main(slot); - - clean_child_exit(0); - } - /* else */ - ap_scoreboard_image->parent[slot].quiescing = 0; - ap_scoreboard_image->parent[slot].pid = pid; - return 0; -} - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->parent[i].pid != 0) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * idle_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 idle_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, j; - int idle_thread_count; - worker_score *ws; - process_score *ps; - int free_length; - int totally_free_length = 0; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - - /* initialize the free_list */ - free_length = 0; - - idle_thread_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - for (i = 0; i < ap_daemons_limit; ++i) { - /* Initialization to satisfy the compiler. It doesn't know - * that ap_threads_per_child is always > 0 */ - int status = SERVER_DEAD; - int any_dying_threads = 0; - int any_dead_threads = 0; - int all_dead_threads = 1; - - if (i >= ap_max_daemons_limit && totally_free_length == idle_spawn_rate) - break; - ps = &ap_scoreboard_image->parent[i]; - for (j = 0; j < ap_threads_per_child; j++) { - ws = &ap_scoreboard_image->servers[i][j]; - status = ws->status; - - /* XXX any_dying_threads is probably no longer needed GLA */ - any_dying_threads = any_dying_threads || - (status == SERVER_GRACEFUL); - any_dead_threads = any_dead_threads || (status == SERVER_DEAD); - all_dead_threads = all_dead_threads && - (status == SERVER_DEAD || - status == SERVER_GRACEFUL); - - /* We consider a starting server as idle because we started it - * at least a cycle ago, and if it still hasn't finished starting - * then we're just going to swamp things worse by forking more. - * So we hopefully won't need to fork more if we count it. - * This depends on the ordering of SERVER_READY and SERVER_STARTING. - */ - if (status <= SERVER_READY && status != SERVER_DEAD && - !ps->quiescing && - ps->generation == ap_my_generation && - /* XXX the following shouldn't be necessary if we clean up - * properly after seg faults, but we're not yet GLA - */ - ps->pid != 0) { - ++idle_thread_count; - } - } - if (any_dead_threads && totally_free_length < idle_spawn_rate - && (!ps->pid /* no process in the slot */ - || ps->quiescing)) { /* or at least one is going away */ - if (all_dead_threads) { - /* great! we prefer these, because the new process can - * start more threads sooner. So prioritize this slot - * by putting it ahead of any slots with active threads. - * - * first, make room by moving a slot that's potentially still - * in use to the end of the array - */ - free_slots[free_length] = free_slots[totally_free_length]; - free_slots[totally_free_length++] = i; - } - else { - /* slot is still in use - back of the bus - */ - free_slots[free_length] = i; - } - ++free_length; - } - /* XXX if (!ps->quiescing) is probably more reliable GLA */ - if (!any_dying_threads) { - last_non_dead = i; - ++total_non_dead; - } - } - ap_max_daemons_limit = last_non_dead + 1; - - if (idle_thread_count > max_spare_threads) { - /* Kill off one child */ - ap_mpm_pod_signal(pod); - idle_spawn_rate = 1; - } - else if (idle_thread_count < min_spare_threads) { - /* terminate the free list */ - if (free_length == 0) { - /* only report this condition once */ - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - ap_server_conf, - "server reached MaxClients setting, consider" - " raising the MaxClients setting"); - reported = 1; - } - idle_spawn_rate = 1; - } - else { - if (free_length > idle_spawn_rate) { - free_length = idle_spawn_rate; - } - if (idle_spawn_rate >= 8) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - ap_server_conf, - "server seems busy, (you may need " - "to increase StartServers, ThreadsPerChild " - "or Min/MaxSpareThreads), " - "spawning %d children, there are around %d idle " - "threads, and %d total children", free_length, - idle_thread_count, total_non_dead); - } - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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 (idle_spawn_rate < MAX_SPAWN_RATE) { - idle_spawn_rate *= 2; - } - } - } - else { - idle_spawn_rate = 1; - } -} - -static void server_main_loop(int remaining_children_to_start) -{ - int child_slot; - apr_exit_why_e exitwhy; - int status, processed_status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); - - if (pid.pid != -1) { - processed_status = ap_process_child_status(&pid, exitwhy, status); - if (processed_status == APEXIT_CHILDFATAL) { - shutdown_pending = 1; - child_fatal = 1; - return; - } - /* non-fatal death... note that it's gone in the scoreboard. */ - child_slot = find_child_by_pid(&pid); - if (child_slot >= 0) { - for (i = 0; i < ap_threads_per_child; i++) - ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD, - (request_rec *) NULL); - - ap_scoreboard_image->parent[child_slot].pid = 0; - ap_scoreboard_image->parent[child_slot].quiescing = 0; - if (processed_status == APEXIT_CHILDSICK) { - /* resource shortage, minimize the fork rate */ - idle_spawn_rate = 1; - } - else if (remaining_children_to_start - && child_slot < ap_daemons_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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_WARNING, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)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_children_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_children(remaining_children_to_start); - remaining_children_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(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - apr_status_t rv; - - ap_log_pid(pconf, ap_pid_fname); - - first_server_limit = server_limit; - first_thread_limit = thread_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit or ThreadLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - - /* Initialize cross-process accept lock */ - ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, - ap_server_root_relative(_pconf, ap_lock_fname), - ap_my_pid); - - rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname, - ap_accept_lock_mech, _pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create accept lock"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - -#if APR_USE_SYSVSEM_SERIALIZE - if (ap_accept_lock_mech == APR_LOCK_DEFAULT || - ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#else - if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#endif - rv = unixd_set_proc_mutex_perms(accept_mutex); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't set permissions on cross-process lock; " - "check User and Group directives"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - } - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - /* fix the generation number in the global score; we just got a new, - * cleared scoreboard - */ - ap_scoreboard_image->global->running_generation = ap_my_generation; - } - - set_signals(); - /* Don't thrash... */ - if (max_spare_threads < min_spare_threads + ap_threads_per_child) - max_spare_threads = min_spare_threads + ap_threads_per_child; - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least daemons_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_children_to_start = ap_daemons_to_start; - if (remaining_children_to_start > ap_daemons_limit) { - remaining_children_to_start = ap_daemons_limit; - } - if (!is_graceful) { - startup_children(remaining_children_to_start); - remaining_children_to_start = 0; - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(accept_mutex), - apr_proc_mutex_defname()); -#endif - restart_pending = shutdown_pending = 0; - mpm_state = AP_MPMQ_RUNNING; - - server_main_loop(remaining_children_to_start); - mpm_state = AP_MPMQ_STOPPING; - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - * (By "gracefully" we don't mean graceful in the same sense as - * "apachectl graceful" where we allow old connections to finish.) - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - - if (!child_fatal) { - /* 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_INFO, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, - ap_server_conf, "caught SIGTERM, shutting down"); - } - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); - /* wake up the children...time to die. But we'll have more soon */ - ap_mpm_pod_killpg(pod, ap_daemons_limit); - - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - } - 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. - */ - ap_mpm_pod_killpg(pod, ap_daemons_limit); - - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - return 0; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int leader_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - apr_status_t rv; - - pconf = p; - ap_server_conf = s; - - if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - - if (!one_process) { - if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); - return DONE; - } - } - return OK; -} - -static int leader_pre_config(apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach, debug, foreground; - ap_directive_t *pdir; - ap_directive_t *max_clients = NULL; - apr_status_t rv; - - mpm_state = AP_MPMQ_STARTING; - - /* make sure that "ThreadsPerChild" gets set before "MaxClients" */ - for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) { - if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) { - if (!max_clients) { - break; /* we're in the clear, got ThreadsPerChild first */ - } - else { - /* now to swap the data */ - ap_directive_t temp; - - temp.directive = pdir->directive; - temp.args = pdir->args; - /* Make sure you don't change 'next', or you may get loops! */ - /* XXX: first_child, parent, and data can never be set - * for these directives, right? -aaron */ - temp.filename = pdir->filename; - temp.line_num = pdir->line_num; - - pdir->directive = max_clients->directive; - pdir->args = max_clients->args; - pdir->filename = max_clients->filename; - pdir->line_num = max_clients->line_num; - - max_clients->directive = temp.directive; - max_clients->args = temp.args; - max_clients->filename = temp.filename; - max_clients->line_num = temp.line_num; - break; - } - } - else if (!max_clients - && strncasecmp(pdir->directive, "MaxClients", 10) == 0) { - max_clients = pdir; - } - } - - debug = ap_exists_config_define("DEBUG"); - - if (debug) { - foreground = one_process = 1; - no_detach = 0; - } - else { - one_process = ap_exists_config_define("ONE_PROCESS"); - no_detach = ap_exists_config_define("NO_DETACH"); - foreground = ap_exists_config_define("FOREGROUND"); - } - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !foreground) { - rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND - : APR_PROC_DETACH_DAEMONIZE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "apr_proc_detach failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - parent_pid = ap_my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_START_DAEMON; - min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - ap_daemons_limit = server_limit; - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static void leader_hooks(apr_pool_t *p) -{ - /* The leader open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - one_process = 0; - - ap_hook_open_logs(leader_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); - /* we need to set the MPM state before other pre-config hooks use MPM query - * to retrieve it, so register as REALLY_FIRST - */ - ap_hook_pre_config(leader_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); -} - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, - const 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, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, - const 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_max_clients (cmd_parms *cmd, void *dummy, - const char *arg) -{ - int max_clients; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - /* It is ok to use ap_threads_per_child here because we are - * sure that it gets set before MaxClients in the pre_config stage. */ - max_clients = atoi(arg); - if (max_clients < ap_threads_per_child) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) must be at least as large", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " large as ThreadsPerChild (%d). Automatically", - ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " increasing MaxClients to %d.", - ap_threads_per_child); - max_clients = ap_threads_per_child; - } - ap_daemons_limit = max_clients / ap_threads_per_child; - if ((max_clients > 0) && (max_clients % ap_threads_per_child)) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) is not an integer multiple", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " of ThreadsPerChild (%d), lowering MaxClients to %d", - ap_threads_per_child, - ap_daemons_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " for a maximum of %d child processes,", - ap_daemons_limit); - max_clients = ap_daemons_limit * ap_threads_per_child; - } - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d would require %d servers,", - max_clients, ap_daemons_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " and would exceed the ServerLimit value of %d.", - server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " Automatically lowering MaxClients to %d. To increase,", - server_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " please see the ServerLimit directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, - const 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 > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "threads, lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_server_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } - return NULL; -} - -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_thread_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d servers,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } - return NULL; -} - -static const command_rec leader_cmds[] = { -UNIX_DAEMON_COMMANDS, -LISTEN_COMMANDS, -AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle children"), -AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, - "Maximum number of children alive at the same time"), -AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, - "Maximum value of MaxClients for this run of Apache"), -AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, - "Maximum worker threads in a server for this run of Apache"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_leader_module = { - MPM20_MODULE_STUFF, - ap_mpm_rewrite_args, /* 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 */ - leader_cmds, /* command apr_table_t */ - leader_hooks /* register_hooks */ -}; - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/mpm.h deleted file mode 100644 index 1db1d1d0..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/mpm.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "scoreboard.h" -#include "unixd.h" - -#ifndef APACHE_MPM_LEADER_H -#define APACHE_MPM_LEADER_H - -#define LEADER_MPM - -#define MPM_NAME "Leader-Follower" - -#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT -#define AP_MPM_WANT_PROCESS_CHILD_STATUS -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_LOCKFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -#define AP_MPM_WANT_SIGNAL_SERVER -#define AP_MPM_WANT_SET_MAX_MEM_FREE -#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER -#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK - -#define AP_MPM_USES_POD 1 -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -#define MPM_ACCEPT_FUNC unixd_accept - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; - -#endif /* APACHE_MPM_LEADER_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/mpm_default.h deleted file mode 100644 index d5a33989..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/leader/mpm_default.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#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 3 -#endif - -/* 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 3 -#endif - -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 25 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/Makefile.in deleted file mode 100644 index 374f1306..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libperchild.la -LTLIBRARY_SOURCES = perchild.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/config5.m4 b/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/config5.m4 deleted file mode 100644 index 368052f5..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/config5.m4 +++ /dev/null @@ -1,6 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "perchild" ; then - AC_CHECK_FUNCS(pthread_kill) - APACHE_FAST_OUTPUT(server/mpm/$MPM_SUBDIR_NAME/Makefile) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/mpm.h deleted file mode 100644 index 84e808db..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/mpm.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "httpd.h" -#include "mpm_default.h" -#include "unixd.h" - -#ifndef APACHE_MPM_PERCHILD_H -#define APACHE_MPM_PERCHILD_H - -#define PERCHILD_MPM - -#define MPM_NAME "Perchild" - -#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT -#define AP_MPM_WANT_PROCESS_CHILD_STATUS -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_LOCKFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -#define AP_MPM_WANT_SIGNAL_SERVER -#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER -#define AP_MPM_USES_POD - -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -#define MPM_ACCEPT_FUNC unixd_accept - -/* Table of child status */ -#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 int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; - -#endif /* APACHE_MPM_PERCHILD_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/mpm_default.h deleted file mode 100644 index ece876b5..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/mpm_default.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREAD -#define DEFAULT_START_THREAD 5 -#endif - -/* Maximum number of *free* server threads --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_SPARE_THREAD -#define DEFAULT_MAX_SPARE_THREAD 10 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_SPARE_THREAD -#define DEFAULT_MIN_SPARE_THREAD 5 -#endif - -/* Number of servers to spawn off by default - */ -#ifndef DEFAULT_NUM_DAEMON -#define DEFAULT_NUM_DAEMON 2 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/perchild.c b/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/perchild.c deleted file mode 100644 index 8b205beb..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/perchild/perchild.c +++ /dev/null @@ -1,2045 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr_hash.h" -#include "apr_strings.h" -#include "apr_pools.h" -#include "apr_portable.h" -#include "apr_file_io.h" -#include "apr_signal.h" - -#define APR_WANT_IOVEC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif - -#if !APR_HAS_THREADS -#error The perchild MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.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_protocol.h" -#include "http_connection.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm.h" -#include "scoreboard.h" -#include "util_filter.h" -#include "apr_poll.h" - -#ifdef HAVE_POLL_H -#include <poll.h> -#endif -#ifdef HAVE_SYS_POLL_H -#include <sys/poll.h> -#endif - -/* ### should be APR-ized */ -#include <grp.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <setjmp.h> -#ifdef HAVE_SYS_PROCESSOR_H -#include <sys/processor.h> /* for bindprocessor() */ -#endif - -/* - * Define some magic numbers that we use for the state of the incomming - * request. These must be < 0 so they don't collide with a file descriptor. - */ -#define AP_PERCHILD_THISCHILD -1 -#define AP_PERCHILD_OTHERCHILD -2 - -/* Limit on the threads per process. Clients will be locked out if more than - * this * 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. - */ -#ifndef DEFAULT_THREAD_LIMIT -#define DEFAULT_THREAD_LIMIT 64 -#endif - -/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_THREAD_LIMIT -#define MAX_THREAD_LIMIT 20000 -#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. - */ -#ifndef DEFAULT_SERVER_LIMIT -#define DEFAULT_SERVER_LIMIT 8 -#endif - -/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_SERVER_LIMIT -#define MAX_SERVER_LIMIT 20000 -#endif - -/* - * Actual definitions of config globals - */ - -static int threads_to_start = 0; /* Worker threads per child */ -static int min_spare_threads = 0; -static int max_spare_threads = 0; -static int max_threads = 0; -static int server_limit = DEFAULT_SERVER_LIMIT; -static int first_server_limit; -static int thread_limit = DEFAULT_THREAD_LIMIT; -static int first_thread_limit; -static int changed_limit_at_restart; -static int num_daemons = 0; -static int curr_child_num = 0; -static int workers_may_exit = 0; -static int requests_this_child; -static int num_listensocks = 0; -static ap_pod_t *pod; -static jmp_buf jmpbuffer; - -struct child_info_t { - uid_t uid; - gid_t gid; - int input; /* The socket descriptor */ - int output; /* The socket descriptor */ -}; - -typedef struct { - const char *sockname; /* The base name for the socket */ - const char *fullsockname; /* socket base name + extension */ - int input; /* The socket descriptor */ - int output; /* The socket descriptor */ -} perchild_server_conf; - -typedef struct child_info_t child_info_t; - -/* Tables used to determine the user and group each child process should - * run as. The hash table is used to correlate a server name with a child - * process. - */ -static child_info_t *child_info_table; -static int *thread_socket_table; -struct ap_ctable *ap_child_table; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with NumServers changes across AP_SIG_GRACEFUL restarts. We - * use this value to optimize routines that have to scan the entire child - * table. - * - * XXX - It might not be worth keeping this code in. There aren't very - * many child processes in this MPM. - */ -int ap_max_daemons_limit = -1; -int ap_threads_per_child; /* XXX not part of API! axe it! */ - -module AP_MODULE_DECLARE_DATA mpm_perchild_module; - -static apr_file_t *pipe_of_death_in = NULL; -static apr_file_t *pipe_of_death_out = NULL; -static apr_thread_mutex_t *pipe_of_death_mutex; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* one_process --- debugging mode variable; can be set from the command line - * with the -X flag. If set, this gets you the child_main loop running - * in the process which originally started up (no detach, no make_child), - * which is a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -static int one_process = 0; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ -static apr_pool_t *thread_pool_parent; /* Parent of per-thread pools */ -static apr_thread_mutex_t *thread_pool_parent_mutex; - -static int child_num; -static unsigned int my_pid; /* Linux getpid() doesn't work except in - main thread. Use this instead */ -/* Keep track of the number of worker threads currently active */ -static int worker_thread_count; -static apr_thread_mutex_t *worker_thread_count_mutex; -static int *worker_thread_free_ids; -static apr_threadattr_t *worker_thread_attr; - -/* Keep track of the number of idle worker threads */ -static int idle_thread_count; -static apr_thread_mutex_t *idle_thread_count_mutex; - -/* Locks for accept serialization */ -#ifdef NO_SERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) APR_SUCCESS -#else -#define SAFE_ACCEPT(stmt) (stmt) -static apr_proc_mutex_t *process_accept_mutex; -#endif /* NO_SERIALIZED_ACCEPT */ -static apr_thread_mutex_t *thread_accept_mutex; - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = server_limit; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = thread_limit; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = max_threads; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = min_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = max_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = num_daemons; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) -{ - if (pchild) { - apr_pool_destroy(pchild); - } - exit(code); -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -static int volatile child_fatal; -/* we don't currently track ap_my_generation, but mod_status - * references it so it must be defined */ -ap_generation_t volatile ap_my_generation=0; - -/* - * 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. - */ - -static 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 */ -static 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) -{ -#ifndef WIN32 - ap_start_restart(sig == AP_SIG_GRACEFUL); -#else - ap_start_restart(1); -#endif -} - -static void set_signals(void) -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; -#endif - - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } - -#ifndef NO_USE_SIGACTION - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGINT)"); -#endif -#ifdef SIGXCPU - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXCPU, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXCPU)"); -#endif -#ifdef SIGXFSZ - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXFSZ, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXFSZ)"); -#endif -#ifdef SIGPIPE - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy - * processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(" AP_SIG_GRACEFUL_STRING ")"); -#else - if (!one_process) { -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef AP_SIG_GRACEFUL - apr_signal(AP_SIG_GRACEFUL, restart); -#endif /* AP_SIG_GRACEFUL */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) -{ - /* XXX - Does this really work? - Manoj */ - return is_graceful; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id, - apr_bucket_alloc_t *bucket_alloc) -{ - conn_rec *current_conn; - int csd; - apr_status_t rv; - int thread_num = conn_id % thread_limit; - ap_sb_handle_t *sbh; - - if ((rv = apr_os_sock_get(&csd, sock)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); - } - - if (thread_socket_table[thread_num] < 0) { - ap_sock_disable_nagle(sock); - } - - ap_create_sb_handle(&sbh, p, conn_id / thread_limit, thread_num); - current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, - sbh, bucket_alloc); - if (current_conn) { - ap_process_connection(current_conn, sock); - ap_lingering_close(current_conn); - } -} - -static int perchild_process_connection(conn_rec *c) -{ - ap_filter_t *f; - apr_bucket_brigade *bb; - core_net_rec *net; - - apr_pool_userdata_get((void **)&bb, "PERCHILD_SOCKETS", c->pool); - if (bb != NULL) { - for (f = c->output_filters; f != NULL; f = f->next) { - if (!strcmp(f->frec->name, "core")) { - break; - } - } - if (f != NULL) { - net = f->ctx; - net->in_ctx = apr_palloc(c->pool, sizeof(*net->in_ctx)); - net->in_ctx->b = bb; - } - } - return DECLINED; -} - - -static void *worker_thread(apr_thread_t *, void *); - -/* Starts a thread as long as we're below max_threads */ -static int start_thread(void) -{ - apr_thread_t *thread; - int rc; - - apr_thread_mutex_lock(worker_thread_count_mutex); - if (worker_thread_count < max_threads - 1) { - rc = apr_thread_create(&thread, worker_thread_attr, worker_thread, - &worker_thread_free_ids[worker_thread_count], pchild); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rc, ap_server_conf, - "apr_thread_create: unable to create worker 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 if we exit. */ - sleep(10); - workers_may_exit = 1; - apr_thread_mutex_unlock(worker_thread_count_mutex); - return 0; - } - else { - worker_thread_count++; - } - } - else { - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - ap_server_conf, - "server reached MaxThreadsPerChild setting, " - "consider raising the MaxThreadsPerChild or " - "NumServers settings"); - reported = 1; - } - apr_thread_mutex_unlock(worker_thread_count_mutex); - return 0; - } - apr_thread_mutex_unlock(worker_thread_count_mutex); - return 1; - -} - -/* Sets workers_may_exit if we received a character on the pipe_of_death */ -static apr_status_t check_pipe_of_death(void **csd, ap_listen_rec *lr, - apr_pool_t *ptrans) -{ - apr_thread_mutex_lock(pipe_of_death_mutex); - if (!workers_may_exit) { - int ret; - char pipe_read_char; - apr_size_t n = 1; - - ret = apr_recv(lr->sd, &pipe_read_char, &n); - if (APR_STATUS_IS_EAGAIN(ret)) { - /* It lost the lottery. It must continue to suffer - * through a life of servitude. */ - } - else { - /* It won the lottery (or something else is very - * wrong). Embrace death with open arms. */ - workers_may_exit = 1; - } - } - apr_thread_mutex_unlock(pipe_of_death_mutex); - return APR_SUCCESS; -} - -static apr_status_t receive_from_other_child(void **csd, ap_listen_rec *lr, - apr_pool_t *ptrans) -{ - struct msghdr msg; - struct cmsghdr *cmsg; - char buffer[HUGE_STRING_LEN * 2], *headers, *body; - int headerslen, bodylen; - struct iovec iov; - int ret, dp; - apr_os_sock_t sd; - apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans); - apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc); - apr_bucket *bucket; - - apr_os_sock_get(&sd, lr->sd); - - iov.iov_base = buffer; - iov.iov_len = sizeof(buffer); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(sd)); - cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sd); - msg.msg_control = cmsg; - msg.msg_controllen = cmsg->cmsg_len; - - ret = recvmsg(sd, &msg, 0); - - memcpy(&dp, CMSG_DATA(cmsg), sizeof(dp)); - - *csd = NULL; /* tell apr_os_sock_put() to allocate new apr_socket_t */ - apr_os_sock_put((apr_socket_t **)csd, &dp, ptrans); - - bucket = apr_bucket_eos_create(alloc); - APR_BRIGADE_INSERT_HEAD(bb, bucket); - bucket = apr_bucket_socket_create(*csd, alloc); - APR_BRIGADE_INSERT_HEAD(bb, bucket); - - body = strchr(iov.iov_base, 0); - if (!body) { - return 1; - } - - body++; - bodylen = strlen(body); - - headers = iov.iov_base; - headerslen = body - headers; - - bucket = apr_bucket_heap_create(body, bodylen, NULL, alloc); - APR_BRIGADE_INSERT_HEAD(bb, bucket); - bucket = apr_bucket_heap_create(headers, headerslen, NULL, alloc); - APR_BRIGADE_INSERT_HEAD(bb, bucket); - - apr_pool_userdata_set(bb, "PERCHILD_SOCKETS", NULL, ptrans); - - return 0; -} - -/* idle_thread_count should be incremented before starting a worker_thread */ - -static void *worker_thread(apr_thread_t *thd, void *arg) -{ - void *csd; - apr_pool_t *tpool; /* Pool for this thread */ - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - volatile int thread_just_started = 1; - int srv; - int thread_num = *((int *) arg); - long conn_id = child_num * thread_limit + thread_num; - apr_pollfd_t *pollset; - apr_status_t rv; - ap_listen_rec *lr, *last_lr = ap_listeners; - int n; - apr_bucket_alloc_t *bucket_alloc; - - apr_thread_mutex_lock(thread_pool_parent_mutex); - apr_pool_create(&tpool, thread_pool_parent); - apr_thread_mutex_unlock(thread_pool_parent_mutex); - apr_pool_create(&ptrans, tpool); - - (void) ap_update_child_status_from_indexes(child_num, thread_num, - SERVER_STARTING, - (request_rec *) NULL); - - bucket_alloc = apr_bucket_alloc_create(apr_thread_pool_get(thd)); - - apr_poll_setup(&pollset, num_listensocks, tpool); - for(lr = ap_listeners; lr != NULL; lr = lr->next) { - int fd; - apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); - - apr_os_sock_get(&fd, lr->sd); - } - - while (!workers_may_exit) { - workers_may_exit |= ((ap_max_requests_per_child != 0) - && (requests_this_child <= 0)); - if (workers_may_exit) break; - if (!thread_just_started) { - apr_thread_mutex_lock(idle_thread_count_mutex); - if (idle_thread_count < max_spare_threads) { - idle_thread_count++; - apr_thread_mutex_unlock(idle_thread_count_mutex); - } - else { - apr_thread_mutex_unlock(idle_thread_count_mutex); - break; - } - } - else { - thread_just_started = 0; - } - - (void) ap_update_child_status_from_indexes(child_num, thread_num, - SERVER_READY, - (request_rec *) NULL); - - apr_thread_mutex_lock(thread_accept_mutex); - if (workers_may_exit) { - apr_thread_mutex_unlock(thread_accept_mutex); - break; - } - if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_proc_mutex_lock failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - - while (!workers_may_exit) { - apr_int16_t event; - srv = apr_poll(pollset, num_listensocks, &n, -1); - - if (srv != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(srv)) { - continue; - } - - /* apr_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, srv, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - workers_may_exit = 1; - } - if (workers_may_exit) break; - - /* find a listener */ - lr = last_lr; - do { - lr = lr->next; - if (lr == NULL) { - lr = ap_listeners; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, lr->sd, pollset); - if (event & (APR_POLLIN)) { - last_lr = lr; - goto got_fd; - } - } while (lr != last_lr); - } - got_fd: - if (!workers_may_exit) { - rv = lr->accept_func(&csd, lr, ptrans); - if (rv == APR_EGENERAL) { - /* E[NM]FILE, ENOMEM, etc */ - workers_may_exit = 1; - } - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - apr_thread_mutex_unlock(thread_accept_mutex); - apr_thread_mutex_lock(idle_thread_count_mutex); - if (idle_thread_count > min_spare_threads) { - idle_thread_count--; - } - else { - if (!start_thread()) { - idle_thread_count--; - } - } - apr_thread_mutex_unlock(idle_thread_count_mutex); - if (setjmp(jmpbuffer) != 1) { - process_socket(ptrans, csd, conn_id, bucket_alloc); - } - else { - thread_socket_table[thread_num] = AP_PERCHILD_THISCHILD; - } - requests_this_child--; - } - else { - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - apr_thread_mutex_unlock(thread_accept_mutex); - apr_thread_mutex_lock(idle_thread_count_mutex); - idle_thread_count--; - apr_thread_mutex_unlock(idle_thread_count_mutex); - break; - } - apr_pool_clear(ptrans); - } - - apr_thread_mutex_lock(thread_pool_parent_mutex); - ap_update_child_status_from_indexes(child_num, thread_num, SERVER_DEAD, - (request_rec *) NULL); - apr_pool_destroy(tpool); - apr_thread_mutex_unlock(thread_pool_parent_mutex); - apr_thread_mutex_lock(worker_thread_count_mutex); - worker_thread_count--; - worker_thread_free_ids[worker_thread_count] = thread_num; - if (worker_thread_count == 0) { - /* All the threads have exited, now finish the shutdown process - * by signalling the sigwait thread */ - kill(my_pid, SIGTERM); - } - apr_thread_mutex_unlock(worker_thread_count_mutex); - - apr_bucket_alloc_destroy(bucket_alloc); - - return NULL; -} - - - -/* Set group privileges. - * - * Note that we use the username as set in the config files, rather than - * the lookup of to uid --- the same uid may have multiple passwd entries, - * with different sets of groups for each. - */ - -static int set_group_privs(uid_t uid, gid_t gid) -{ - if (!geteuid()) { - const char *name; - - /* Get username if passed as a uid */ - - struct passwd *ent; - - if ((ent = getpwuid(uid)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "getpwuid: couldn't determine user name from uid %u, " - "you probably need to modify the User directive", - (unsigned)uid); - return -1; - } - - name = ent->pw_name; - - /* - * Set the GID before initgroups(), since on some platforms - * setgid() is known to zap the group list. - */ - if (setgid(gid) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setgid: unable to set group id to Group %u", - (unsigned)gid); - return -1; - } - - /* Reset `groups' attributes. */ - - if (initgroups(name, gid) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "initgroups: unable to set groups for User %s " - "and Group %u", name, (unsigned)gid); - return -1; - } - } - return 0; -} - - -static int perchild_setup_child(int childnum) -{ - child_info_t *ug = &child_info_table[childnum]; - - if (ug->uid == -1 && ug->gid == -1) { - return unixd_setup_child(); - } - if (set_group_privs(ug->uid, ug->gid)) { - return -1; - } - /* Only try to switch if we're running as root */ - if (!geteuid() - && ( -#ifdef _OSD_POSIX - os_init_job_environment(server_conf, unixd_config.user_name, - one_process) != 0 || -#endif - setuid(ug->uid) == -1)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setuid: unable to change to uid: %ld", - (long) ug->uid); - return -1; - } - return 0; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - just_die(signum); - return 1; - } - return 0; -} - -typedef struct perchild_header { - char *headers; - apr_pool_t *p; -} perchild_header; - -/* Send a single HTTP header field to the client. Note that this function - * is used in calls to table_do(), so their interfaces are co-dependent. - * In other words, don't change this one without checking table_do in alloc.c. - * It returns true unless there was a write error of some kind. - */ -static int perchild_header_field(perchild_header *h, - const char *fieldname, const char *fieldval) -{ - apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL); - return 1; -} - - -static void child_main(int child_num_arg) -{ - int i; - apr_status_t rv; - apr_socket_t *sock = NULL; - ap_listen_rec *lr; - - my_pid = getpid(); - ap_fatal_signal_child_setup(ap_server_conf); - child_num = child_num_arg; - apr_pool_create(&pchild, pconf); - - for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) { - continue; - } - - apr_os_sock_put(&sock, &child_info_table[child_num].input, pconf); - lr->next = apr_palloc(pconf, sizeof(*lr)); - lr->next->sd = sock; - lr->next->active = 1; - lr->next->accept_func = receive_from_other_child; - lr->next->next = NULL; - lr = lr->next; - num_listensocks++; - - /*stuff to do before we switch id's, so we have permissions.*/ - - rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&process_accept_mutex, - ap_lock_fname, pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (perchild_setup_child(child_num)) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /*done with init critical section */ - - apr_setup_signal_thread(); - - requests_this_child = ap_max_requests_per_child; - - - /* Setup worker threads */ - - if (threads_to_start > max_threads) { - threads_to_start = max_threads; - } - idle_thread_count = threads_to_start; - worker_thread_count = 0; - worker_thread_free_ids = (int *)apr_pcalloc(pchild, thread_limit * sizeof(int)); - for (i = 0; i < max_threads; i++) { - worker_thread_free_ids[i] = i; - } - apr_pool_create(&thread_pool_parent, pchild); - apr_thread_mutex_create(&thread_pool_parent_mutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - apr_thread_mutex_create(&idle_thread_count_mutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - apr_thread_mutex_create(&worker_thread_count_mutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - apr_thread_mutex_create(&pipe_of_death_mutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - apr_thread_mutex_create(&thread_accept_mutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - - apr_threadattr_create(&worker_thread_attr, pchild); - apr_threadattr_detach_set(worker_thread_attr, 1); - - /* We are creating worker threads right now */ - for (i=0; i < threads_to_start; i++) { - /* start_thread shouldn't fail here */ - if (!start_thread()) { - break; - } - } - - apr_signal_thread(check_signal); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_child_table[slot].pid = getpid(); - ap_child_table[slot].status = SERVER_ALIVE; - child_main(slot); - } - (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, - (request_rec *) NULL); - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "fork: Unable to fork new process"); - /* 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; - } - - if (!pid) { -#ifdef HAVE_BINDPROCESSOR - /* By default, AIX binds to a single processor. This bit unbinds - * children which will then bind to another CPU. - */ - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, - ap_server_conf, "processor unbind failed %d", status); - } -#endif - - RAISE_SIGSTOP(MAKE_CHILD); - - /* XXX - For an unthreaded server, a signal handler will be necessary - * apr_signal(SIGTERM, just_die); - */ - child_main(slot); - clean_child_exit(0); - } - /* else */ - ap_child_table[slot].pid = pid; - ap_child_table[slot].status = SERVER_ALIVE; - - return 0; -} - -/* start up a bunch of children */ -static int startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < num_daemons; ++i) { - if (ap_child_table[i].pid) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } - return number_to_start; -} - - -/* - * spawn_rate is the number of children that will be spawned on the - * next maintenance cycle if there aren't enough 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_child_maintenance(void) -{ - int i; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead = -1; - - /* initialize the free_list */ - free_length = 0; - - for (i = 0; i < num_daemons; ++i) { - if (ap_child_table[i].pid == 0) { - if (free_length < spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else { - last_non_dead = i; - } - - if (i >= ap_max_daemons_limit && free_length >= spawn_rate) { - break; - } - } - ap_max_daemons_limit = last_non_dead + 1; - - if (free_length > 0) { - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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_children_to_start) -{ - int child_slot; - apr_exit_why_e exitwhy; - int status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); - - if (pid.pid != -1) { - if (ap_process_child_status(&pid, exitwhy, status) - == APEXIT_CHILDFATAL) { - shutdown_pending = 1; - child_fatal = 1; - return; - } - /* non-fatal death... note that it's gone in the child table and - * clean out the status table. */ - child_slot = -1; - for (i = 0; i < ap_max_daemons_limit; ++i) { - if (ap_child_table[i].pid == pid.pid) { - child_slot = i; - break; - } - } - if (child_slot >= 0) { - ap_child_table[child_slot].pid = 0; - ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD, - (request_rec *) NULL); - - - if (remaining_children_to_start - && child_slot < num_daemons) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&pid, status) == 0) { - /* handled */ -#endif - } - else if (is_graceful) { - /* Great, we've probably just lost a slot in the - * child table. Somehow we don't know about this - * child. - */ - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)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_children_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. - */ - remaining_children_to_start = \ - startup_children(remaining_children_to_start); - /* 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_child_maintenance(); - } -} - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - int i; - apr_status_t rv; - apr_size_t one = 1; - ap_listen_rec *lr; - apr_socket_t *sock = NULL; - int fd; - - ap_log_pid(pconf, ap_pid_fname); - - first_server_limit = server_limit; - first_thread_limit = thread_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit or ThreadLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - - ap_server_conf = s; - - if ((ap_accept_lock_mech == APR_LOCK_SYSVSEM) || - (ap_accept_lock_mech == APR_LOCK_POSIXSEM)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "Server configured for an accept lock mechanism that " - "cannot be used with perchild. Falling back to FCNTL."); - ap_accept_lock_mech = APR_LOCK_FCNTL; - } - - /* Initialize cross-process accept lock */ - ap_lock_fname = apr_psprintf(_pconf, "%s.%u", - ap_server_root_relative(_pconf, ap_lock_fname), - my_pid); - rv = SAFE_ACCEPT(apr_proc_mutex_create(&process_accept_mutex, - ap_lock_fname, ap_accept_lock_mech, - _pconf)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create cross-process lock"); - return 1; - } - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - return 1; - } - } - /* Initialize the child table */ - if (!is_graceful) { - for (i = 0; i < server_limit; i++) { - ap_child_table[i].pid = 0; - } - } - - /* We need to put the new listeners at the end of the ap_listeners - * list. If we don't, then the pool will be cleared before the - * open_logs phase is called for the second time, and ap_listeners - * will have only invalid data. If that happens, then the sockets - * that we opened using make_sock() will be lost, and the server - * won't start. - */ - for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) { - continue; - } - - apr_os_file_get(&fd, pipe_of_death_in); - apr_os_sock_put(&sock, &fd, pconf); - lr->next = apr_palloc(pconf, sizeof(*lr)); - lr->next->sd = sock; - lr->next->active = 1; - lr->next->accept_func = check_pipe_of_death; - lr->next->next = NULL; - lr = lr->next; - num_listensocks++; - - set_signals(); - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them AP_SIG_GRACEFUL). This happens - * pretty rapidly... and for each one that exits we'll start a new one - * until we reach at least daemons_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_children_to_start = num_daemons; - if (!is_graceful) { - remaining_children_to_start = \ - startup_children(remaining_children_to_start); - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(process_accept_mutex), - apr_proc_mutex_defname()); -#endif - restart_pending = shutdown_pending = 0; - - server_main_loop(remaining_children_to_start); - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - - if (!child_fatal) { - /* 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_INFO, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, - ap_server_conf, "caught SIGTERM, shutting down"); - } - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - if (is_graceful) { - char char_of_death = '!'; - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, - ap_server_conf, AP_SIG_GRACEFUL_STRING " received. " - "Doing graceful restart"); - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - for (i = 0; i < num_daemons; ++i) { - if (ap_child_table[i].pid) { - ap_child_table[i].status = SERVER_DYING; - } - } - /* give the children the signal to die */ - for (i = 0; i < num_daemons;) { - if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, - &one)) != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(rv)) continue; - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, - "write pipe_of_death"); - } - i++; - } - } - 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. - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, - ap_server_conf, "SIGHUP received. Attempting to restart"); - } - return 0; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int perchild_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - apr_status_t rv; - - pconf = p; - ap_server_conf = s; - - if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - - ap_log_pid(pconf, ap_pid_fname); - - if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); - return DONE; - } - - if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, - pconf)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_create (pipe_of_death)"); - exit(1); - } - if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_timeout_set (pipe_of_death)"); - exit(1); - } - - return OK; -} - -static int perchild_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach, debug, foreground; - ap_directive_t *pdir; - int i; - int tmp_server_limit = DEFAULT_SERVER_LIMIT; - int tmp_thread_limit = DEFAULT_THREAD_LIMIT; - apr_status_t rv; - - debug = ap_exists_config_define("DEBUG"); - - if (debug) { - foreground = one_process = 1; - no_detach = 0; - } - else { - one_process = ap_exists_config_define("ONE_PROCESS"); - no_detach = ap_exists_config_define("NO_DETACH"); - foreground = ap_exists_config_define("FOREGROUND"); - } - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !foreground) { - rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND - : APR_PROC_DETACH_DAEMONIZE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "apr_proc_detach failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - - my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - num_daemons = DEFAULT_NUM_DAEMON; - threads_to_start = DEFAULT_START_THREAD; - min_spare_threads = DEFAULT_MIN_SPARE_THREAD; - max_spare_threads = DEFAULT_MAX_SPARE_THREAD; - max_threads = thread_limit; - ap_pid_fname = DEFAULT_PIDLOG; - ap_lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - curr_child_num = 0; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - /* we need to know ServerLimit and ThreadLimit before we start processing - * the tree because we need to already have allocated child_info_table - */ - for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) { - if (!strcasecmp(pdir->directive, "ServerLimit")) { - if (atoi(pdir->args) > tmp_server_limit) { - tmp_server_limit = atoi(pdir->args); - if (tmp_server_limit > MAX_SERVER_LIMIT) { - tmp_server_limit = MAX_SERVER_LIMIT; - } - } - } - else if (!strcasecmp(pdir->directive, "ThreadLimit")) { - if (atoi(pdir->args) > tmp_thread_limit) { - tmp_thread_limit = atoi(pdir->args); - if (tmp_thread_limit > MAX_THREAD_LIMIT) { - tmp_thread_limit = MAX_THREAD_LIMIT; - } - } - } - } - - child_info_table = (child_info_t *)apr_pcalloc(p, tmp_server_limit * sizeof(child_info_t)); - for (i = 0; i < tmp_server_limit; i++) { - child_info_table[i].uid = -1; - child_info_table[i].gid = -1; - child_info_table[i].input = -1; - child_info_table[i].output = -1; - } - - return OK; -} - -static int pass_request(request_rec *r) -{ - int rv; - apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module); - struct msghdr msg; - struct cmsghdr *cmsg; - int sfd; - struct iovec iov[2]; - conn_rec *c = r->connection; - apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc); - apr_bucket_brigade *sockbb; - char request_body[HUGE_STRING_LEN] = "\0"; - apr_size_t l = sizeof(request_body); - perchild_header h; - apr_bucket *sockbuck; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(r->server->module_config, - &mpm_perchild_module); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "passing request to another child. Vhost: %s, child %d %d", - apr_table_get(r->headers_in, "Host"), child_num, sconf->output); - ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, - 0); - - for (sockbuck = APR_BRIGADE_FIRST(bb); sockbuck != APR_BRIGADE_SENTINEL(bb); - sockbuck = APR_BUCKET_NEXT(sockbuck)) { - if (APR_BUCKET_IS_SOCKET(sockbuck)) { - break; - } - } - - if (!sockbuck) { - } - sockbb = apr_brigade_split(bb, sockbuck); - - if (apr_brigade_flatten(bb, request_body, &l) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Unable to flatten brigade, declining request"); - return DECLINED; - } - - apr_os_sock_get(&sfd, thesock); - - h.p = r->pool; - h.headers = apr_pstrcat(h.p, r->the_request, CRLF, "Host: ", r->hostname, - CRLF, NULL); - apr_table_do((int (*) (void *, const char *, const char *)) - perchild_header_field, (void *) &h, r->headers_in, NULL); - h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL); - - iov[0].iov_base = h.headers; - iov[0].iov_len = strlen(h.headers) + 1; - iov[1].iov_base = request_body; - iov[1].iov_len = l + 1; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = 2; - - cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sfd)); - cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sfd); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - memcpy(CMSG_DATA(cmsg), &sfd, sizeof(sfd)); - - msg.msg_control = cmsg; - msg.msg_controllen = cmsg->cmsg_len; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Writing message to %d, passing sd: %d", sconf->output, sfd); - - if ((rv = sendmsg(sconf->output, &msg, 0)) == -1) { - apr_pool_destroy(r->pool); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Writing message failed %d %d", rv, errno); - return -1; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Writing message succeeded %d", rv); - - apr_pool_destroy(r->pool); - return 1; -} - -static char *make_perchild_socket(const char *fullsockname, int sd[2]) -{ - socketpair(PF_UNIX, SOCK_STREAM, 0, sd); - return NULL; -} - -static int perchild_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - int i; - server_rec *sr; - perchild_server_conf *sconf; - int def_sd[2]; - - def_sd[0] = -1; - def_sd[1] = -1; - - for (sr = s; sr; sr = sr->next) { - sconf = (perchild_server_conf *)ap_get_module_config(sr->module_config, - &mpm_perchild_module); - - if (sconf->input == -1) { - sconf->fullsockname = apr_pstrcat(sr->process->pool, - sconf->sockname, ".DEFAULT", NULL); - if (def_sd[0] == -1) { - if (!make_perchild_socket(sconf->fullsockname, def_sd)) { - /* log error */ - } - } - sconf->input = def_sd[0]; - sconf->output = def_sd[1]; - } - } - - for (i = 0; i < num_daemons; i++) { - if (child_info_table[i].uid == -1) { - child_info_table[i].input = def_sd[0]; - child_info_table[i].output = def_sd[1]; - } - } - - thread_socket_table = (int *)apr_pcalloc(p, thread_limit * sizeof(int)); - for (i = 0; i < thread_limit; i++) { - thread_socket_table[i] = AP_PERCHILD_THISCHILD; - } - ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable)); - - return OK; -} - -static int perchild_post_read(request_rec *r) -{ - int thread_num = r->connection->id % thread_limit; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(r->server->module_config, - &mpm_perchild_module); - - if (thread_socket_table[thread_num] != AP_PERCHILD_THISCHILD) { - apr_socket_t *csd = NULL; - - apr_os_sock_put(&csd, &thread_socket_table[thread_num], - r->connection->pool); - ap_sock_disable_nagle(csd); - ap_set_module_config(r->connection->conn_config, &core_module, csd); - return OK; - } - else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Determining if request should be passed. " - "Child Num: %d, SD: %d, sd from table: %d, hostname from server: %s", child_num, - sconf->input, child_info_table[child_num].input, - r->server->server_hostname); - /* sconf is the server config for this vhost, so if our socket - * is not the same that was set in the config, then the request - * needs to be passed to another child. */ - if (sconf->input != child_info_table[child_num].input) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Passing request."); - if (pass_request(r) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - ap_server_conf, "Could not pass request to proper " - "child, request will not be honored."); - } - longjmp(jmpbuffer, 1); - } - return OK; - } - return OK; -} - -static void perchild_hooks(apr_pool_t *p) -{ - /* The perchild open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - one_process = 0; - - ap_hook_open_logs(perchild_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); - ap_hook_pre_config(perchild_pre_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(perchild_post_config, NULL, NULL, APR_HOOK_MIDDLE); - - /* Both of these must be run absolutely first. If this request isn't for - * this server then we need to forward it to the proper child. No sense - * tying up this server running more post_read request hooks if it is - * just going to be forwarded along. The process_connection hook allows - * perchild to receive the passed request correctly, by automatically - * filling in the core_input_filter's ctx pointer. - */ - ap_hook_post_read_request(perchild_post_read, NULL, NULL, - APR_HOOK_REALLY_FIRST); - ap_hook_process_connection(perchild_process_connection, NULL, NULL, - APR_HOOK_REALLY_FIRST); -} - -static const char *set_num_daemons(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - num_daemons = atoi(arg); - if (num_daemons > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: NumServers of %d exceeds ServerLimit value " - "of %d servers,", num_daemons, server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering NumServers to %d. To increase, please " - "see the", server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ServerLimit directive."); - num_daemons = server_limit; - } - else if (num_daemons < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require NumServers > 0, setting to 1"); - num_daemons = 1; - } - return NULL; -} - -static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - threads_to_start = atoi(arg); - if (threads_to_start > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: StartThreads of %d exceeds ThreadLimit value" - " of %d threads,", threads_to_start, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering StartThreads to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - } - else if (threads_to_start < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require StartThreads > 0, setting to 1"); - threads_to_start = 1; - } - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, - const 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, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_spare_threads = atoi(arg); - if (max_spare_threads >= thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareThreads set higher than"); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "ThreadLimit. Resetting to %d", thread_limit); - max_spare_threads = thread_limit; - } - return NULL; -} - -static const char *set_max_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_threads = atoi(arg); - if (max_threads > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MaxThreadsPerChild set higher than"); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "ThreadLimit. Resetting to %d", thread_limit); - max_threads = thread_limit; - } - return NULL; -} - -static const char *set_child_per_uid(cmd_parms *cmd, void *dummy, const char *u, - const char *g, const char *num) -{ - int i; - int max_this_time = atoi(num) + curr_child_num; - - - for (i = curr_child_num; i < max_this_time; i++, curr_child_num++) { - if (i > num_daemons) { - return "Trying to use more child ID's than NumServers. Increase " - "NumServers in your config file."; - } - - child_info_table[i].uid = ap_uname2id(u); - child_info_table[i].gid = ap_gname2id(g); - -#ifndef BIG_SECURITY_HOLE - if (child_info_table[i].uid == 0 || child_info_table[i].gid == 0) { - return "Assigning root user/group to a child."; - } -#endif - } - return NULL; -} - -static const char *assign_childuid(cmd_parms *cmd, void *dummy, const char *uid, - const char *gid) -{ - int i; - int matching = 0; - int u = ap_uname2id(uid); - int g = ap_gname2id(gid); - const char *errstr; - int socks[2]; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(cmd->server->module_config, - &mpm_perchild_module); - - sconf->fullsockname = apr_pstrcat(cmd->pool, sconf->sockname, ".", uid, - ":", gid, NULL); - - if ((errstr = make_perchild_socket(sconf->fullsockname, socks))) { - return errstr; - } - - sconf->input = socks[0]; - sconf->output = socks[1]; - - for (i = 0; i < num_daemons; i++) { - if (u == child_info_table[i].uid && g == child_info_table[i].gid) { - child_info_table[i].input = sconf->input; - child_info_table[i].output = sconf->output; - matching++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, - "filling out child_info_table; UID: %d, GID: %d, " - "SD: %d %d, OUTPUT: %d %d, Child Num: %d", - child_info_table[i].uid, child_info_table[i].gid, - sconf->input, child_info_table[i].input, sconf->output, - child_info_table[i].output, i); - } - } - - if (!matching) { - return "Unable to find process with matching uid/gid."; - } - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_server_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } - return NULL; -} - -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_thread_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d servers,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } - return NULL; -} - -static const command_rec perchild_cmds[] = { -UNIX_DAEMON_COMMANDS, -LISTEN_COMMANDS, -AP_INIT_TAKE1("NumServers", set_num_daemons, NULL, RSRC_CONF, - "Number of children alive at the same time"), -AP_INIT_TAKE1("StartThreads", set_threads_to_start, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle threads per child, to handle " - "request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle threads per child"), -AP_INIT_TAKE1("MaxThreadsPerChild", set_max_threads, NULL, RSRC_CONF, - "Maximum number of threads per child"), -AP_INIT_TAKE3("ChildperUserID", set_child_per_uid, NULL, RSRC_CONF, - "Specify a User and Group for a specific child process."), -AP_INIT_TAKE2("AssignUserID", assign_childuid, NULL, RSRC_CONF, - "Tie a virtual host to a specific child process."), -AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, - "Maximum value of NumServers for this run of Apache"), -AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, - "Maximum worker threads in a server for this run of Apache"), -{ NULL } -}; - -static void *perchild_create_config(apr_pool_t *p, server_rec *s) -{ - perchild_server_conf *c = (perchild_server_conf *) - apr_pcalloc(p, sizeof(perchild_server_conf)); - - c->input = -1; - c->output = -1; - return c; -} - -module AP_MODULE_DECLARE_DATA mpm_perchild_module = { - MPM20_MODULE_STUFF, - ap_mpm_rewrite_args, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - perchild_create_config, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - perchild_cmds, /* command apr_table_t */ - perchild_hooks /* register_hooks */ -}; - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/Makefile.in deleted file mode 100644 index ea0acb69..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libthreadpool.la -LTLIBRARY_SOURCES = threadpool.c pod.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/README b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/README deleted file mode 100644 index 86e8524c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/README +++ /dev/null @@ -1,12 +0,0 @@ -Threadpool MPM: -This is an experimental variant of the standard worker MPM. -Rather than queuing connections like the worker MPM, the threadpool -MPM queues idle worker threads and hands each accepted connection -to the next available worker. - -The threadpool MPM can't match the performance of the worker MPM -in benchmark testing. As of 2.0.39, some of the key load-throtting -concepts from the threadpool MPM have been incorporated into the -worker MPM. The threadpool code is useful primarily as a research -platform; for general-purpose use, and for any production environments, -use worker instead. diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/config5.m4 b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/config5.m4 deleted file mode 100644 index 667b534a..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/config5.m4 +++ /dev/null @@ -1,6 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "threadpool" ; then - AC_CHECK_FUNCS(pthread_kill) - APACHE_FAST_OUTPUT(server/mpm/$MPM_SUBDIR_NAME/Makefile) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/mpm.h deleted file mode 100644 index 222040bd..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/mpm.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "scoreboard.h" -#include "unixd.h" - -#ifndef APACHE_MPM_THREADPOOL_H -#define APACHE_MPM_THREADPOOL_H - -#define THREADPOOL_MPM - -#define MPM_NAME "ThreadPool" - -#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT -#define AP_MPM_WANT_PROCESS_CHILD_STATUS -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_LOCKFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -#define AP_MPM_WANT_SIGNAL_SERVER -#define AP_MPM_WANT_SET_MAX_MEM_FREE -#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER -#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK - -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -#define MPM_ACCEPT_FUNC unixd_accept - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; - -#endif /* APACHE_MPM_THREADPOOL_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/mpm_default.h deleted file mode 100644 index d5a33989..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/mpm_default.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#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 3 -#endif - -/* 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 3 -#endif - -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 25 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/pod.c b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/pod.c deleted file mode 100644 index 2f26130c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/pod.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "pod.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod) -{ - apr_status_t rv; - - *pod = apr_palloc(p, sizeof(**pod)); - rv = apr_file_pipe_create(&((*pod)->pod_in), &((*pod)->pod_out), p); - if (rv != APR_SUCCESS) { - return rv; - } -/* - apr_file_pipe_timeout_set((*pod)->pod_in, 0); -*/ - (*pod)->p = p; - - return APR_SUCCESS; -} - -AP_DECLARE(int) ap_mpm_pod_check(ap_pod_t *pod) -{ - char c; - apr_os_file_t fd; - int rc; - - /* we need to surface EINTR so we'll have to grab the - * native file descriptor and do the OS read() ourselves - */ - apr_os_file_get(&fd, pod->pod_in); - rc = read(fd, &c, 1); - if (rc == 1) { - switch(c) { - case RESTART_CHAR: - return AP_RESTART; - case GRACEFUL_CHAR: - return AP_GRACEFUL; - } - } - return AP_NORESTART; -} - -AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod) -{ - apr_status_t rv; - - rv = apr_file_close(pod->pod_out); - if (rv != APR_SUCCESS) { - return rv; - } - - rv = apr_file_close(pod->pod_in); - if (rv != APR_SUCCESS) { - return rv; - } - return rv; -} - -static apr_status_t pod_signal_internal(ap_pod_t *pod, int graceful) -{ - apr_status_t rv; - char char_of_death = graceful ? GRACEFUL_CHAR : RESTART_CHAR; - apr_size_t one = 1; - - do { - rv = apr_file_write(pod->pod_out, &char_of_death, &one); - } while (APR_STATUS_IS_EINTR(rv)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, - "write pipe_of_death"); - } - return rv; -} - -AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod, int graceful) -{ - return pod_signal_internal(pod, graceful); -} - -AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num, int graceful) -{ - int i; - apr_status_t rv = APR_SUCCESS; - - for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = pod_signal_internal(pod, graceful); - } -} - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/pod.h b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/pod.h deleted file mode 100644 index 21651e6f..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/pod.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr.h" -#include "apr_strings.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_main.h" -#include "mpm.h" -#include "mpm_common.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "mpm_default.h" - -#define RESTART_CHAR '$' -#define GRACEFUL_CHAR '!' - -#define AP_RESTART 0 -#define AP_GRACEFUL 1 - -typedef struct ap_pod_t ap_pod_t; - -struct ap_pod_t { - apr_file_t *pod_in; - apr_file_t *pod_out; - apr_pool_t *p; -}; - -AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod); -AP_DECLARE(int) ap_mpm_pod_check(ap_pod_t *pod); -AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod); -AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod, int graceful); -AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num, int graceful); diff --git a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/threadpool.c b/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/threadpool.c deleted file mode 100644 index 50de500e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/experimental/threadpool/threadpool.c +++ /dev/null @@ -1,2229 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* The purpose of this MPM is to fix the design flaws in the threaded - * model. Because of the way that pthreads and mutex locks interact, - * it is basically impossible to cleanly gracefully shutdown a child - * process if multiple threads are all blocked in accept. This model - * fixes those problems. - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" -#include "apr_poll.h" -#include "apr_thread_mutex.h" -#include "apr_thread_cond.h" -#include "apr_proc_mutex.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if APR_HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifdef HAVE_SYS_PROCESSOR_H -#include <sys/processor.h> /* for bindprocessor() */ -#endif - -#if !APR_HAS_THREADS -#error The Worker MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.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 "pod.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "scoreboard.h" -#include "mpm_default.h" - -#include <signal.h> -#include <limits.h> /* for INT_MAX */ - -/* 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. - */ -#ifndef DEFAULT_SERVER_LIMIT -#define DEFAULT_SERVER_LIMIT 16 -#endif - -/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_SERVER_LIMIT -#define MAX_SERVER_LIMIT 20000 -#endif - -/* Limit on the threads per process. Clients will be locked out if more than - * this * 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. - */ -#ifndef DEFAULT_THREAD_LIMIT -#define DEFAULT_THREAD_LIMIT 64 -#endif - -/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_THREAD_LIMIT -#define MAX_THREAD_LIMIT 20000 -#endif - -/* - * Actual definitions of config globals - */ - -int ap_threads_per_child = 0; /* Worker threads per child */ -static int ap_daemons_to_start = 0; -static int min_spare_threads = 0; -static int max_spare_threads = 0; -static int ap_daemons_limit = 0; -static int server_limit = DEFAULT_SERVER_LIMIT; -static int first_server_limit; -static int thread_limit = DEFAULT_THREAD_LIMIT; -static int first_thread_limit; -static int changed_limit_at_restart; -static int dying = 0; -static int workers_may_exit = 0; -static int start_thread_may_exit = 0; -static int listener_may_exit = 0; -static int requests_this_child; -static int num_listensocks = 0; -static int resource_shortage = 0; -static int mpm_state = AP_MPMQ_STARTING; - -/* The structure used to pass unique initialization info to each thread */ -typedef struct { - int pid; - int tid; - int sd; -} proc_info; - -/* Structure used to pass information to the thread responsible for - * creating the rest of the threads. - */ -typedef struct { - apr_thread_t **threads; - apr_thread_t *listener; - int child_num_arg; - apr_threadattr_t *threadattr; -} thread_starter; - -#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t) - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We - * use this value to optimize routines that have to scan the entire - * scoreboard. - */ -int ap_max_daemons_limit = -1; - -static ap_pod_t *pod; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* The worker MPM respects a couple of runtime flags that can aid - * in debugging. Setting the -DNO_DETACH flag will prevent the root process - * from detaching from its controlling terminal. Additionally, setting - * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the - * child_main loop running in the process which originally started up. - * This gives you a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -static int one_process = 0; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main - thread. Use this instead */ -static pid_t parent_pid; -static apr_os_thread_t *listener_os_thread; - -/* Locks for accept serialization */ -static apr_proc_mutex_t *accept_mutex; - -#if APR_O_NONBLOCK_INHERITED -#undef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#endif /* APR_O_NONBLOCK_INHERITED */ - -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS) -#else -#define SAFE_ACCEPT(stmt) (stmt) -#endif - -/* The LISTENER_SIGNAL signal will be sent from the main thread to the - * listener thread to wake it up for graceful termination (what a child - * process from an old generation does when the admin does "apachectl - * graceful"). This signal will be blocked in all threads of a child - * process except for the listener thread. - */ -#define LISTENER_SIGNAL SIGHUP - - -/* Possible states of a worker thread. */ -typedef enum { - WORKER_IDLE, - WORKER_BUSY, - WORKER_TERMINATED -} worker_state_e; - -/* Structure used to wake up an idle worker thread - */ -typedef struct { - apr_pool_t *pool; - apr_socket_t *csd; - worker_state_e state; - apr_thread_cond_t *cond; - apr_thread_mutex_t *mutex; -} worker_wakeup_info; - -/* Structure used to hold a stack of idle worker threads - */ -typedef struct { - apr_thread_mutex_t *mutex; - apr_thread_cond_t *cond; - worker_wakeup_info **stack; - apr_size_t nelts; - apr_size_t nalloc; - int terminated; -} worker_stack; - -static worker_stack* worker_stack_create(apr_pool_t *pool, apr_size_t max) -{ - apr_status_t rv; - worker_stack *stack = (worker_stack *)apr_palloc(pool, sizeof(*stack)); - - if ((rv = apr_thread_mutex_create(&stack->mutex, APR_THREAD_MUTEX_DEFAULT, - pool)) != APR_SUCCESS) { - return NULL; - } - if ((rv = apr_thread_cond_create(&stack->cond, pool)) != APR_SUCCESS) { - return NULL; - } - stack->nelts = 0; - stack->nalloc = max; - stack->stack = - (worker_wakeup_info **)apr_palloc(pool, stack->nalloc * - sizeof(worker_wakeup_info *)); - stack->terminated = 0; - return stack; -} - -static apr_status_t worker_stack_wait(worker_stack *stack, - worker_wakeup_info *wakeup) -{ - apr_status_t rv; - - wakeup->state = WORKER_IDLE; - - if ((rv = apr_thread_mutex_lock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - if (stack->terminated) { - if ((rv = apr_thread_mutex_unlock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - return APR_EOF; - } - if (stack->nelts == stack->nalloc) { - if ((rv = apr_thread_mutex_unlock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - return APR_ENOSPC; - } - stack->stack[stack->nelts] = wakeup; - /* Signal a blocking listener thread only if we just made the - * stack non-empty. */ - if (stack->nelts++ == 0) { - (void)apr_thread_cond_signal(stack->cond); - } - if ((rv = apr_thread_mutex_unlock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - - /* At this point we've already added this worker to the stack, now - * we just wait until the listener has accept()ed a connection - * for us. */ - if ((rv = apr_thread_mutex_lock(wakeup->mutex)) != APR_SUCCESS) { - return rv; - } - while (wakeup->state == WORKER_IDLE) { - if ((rv = apr_thread_cond_wait(wakeup->cond, wakeup->mutex)) != - APR_SUCCESS) { - return rv; - } - } - if ((rv = apr_thread_mutex_unlock(wakeup->mutex)) != APR_SUCCESS) { - return rv; - } - return APR_SUCCESS; -} - -static apr_status_t worker_stack_pop(worker_stack *stack, - worker_wakeup_info **worker) -{ - apr_status_t rv; - if ((rv = apr_thread_mutex_lock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - AP_DEBUG_ASSERT(stack->nelts >= 0); - while ((stack->nelts == 0) && (!stack->terminated)) { - rv = apr_thread_cond_wait(stack->cond, stack->mutex); - if (rv != APR_SUCCESS) { - apr_status_t rv2; - rv2 = apr_thread_mutex_unlock(stack->mutex); - if (rv2 != APR_SUCCESS) { - return rv2; - } - return rv; - } - } - if (stack->terminated) { - if ((rv = apr_thread_mutex_unlock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - return APR_EOF; - } - *worker = stack->stack[--stack->nelts]; - if ((rv = apr_thread_mutex_unlock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - return APR_SUCCESS; -} - -static apr_status_t worker_stack_terminate(worker_stack *stack) -{ - apr_status_t rv; - worker_wakeup_info *worker; - - if ((rv = apr_thread_mutex_lock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - stack->terminated = 1; - /* Wake up the listener thread. Although there will never be - * more than one thread blocking on this condition, broadcast - * just in case. */ - apr_thread_cond_broadcast(stack->cond); - while (stack->nelts) { - worker = stack->stack[--stack->nelts]; - apr_thread_mutex_lock(worker->mutex); - worker->csd = 0; - worker->state = WORKER_TERMINATED; - apr_thread_cond_signal(worker->cond); - apr_thread_mutex_unlock(worker->mutex); - } - if ((rv = apr_thread_mutex_unlock(stack->mutex)) != APR_SUCCESS) { - return rv; - } - return APR_SUCCESS; -} - -static worker_stack *idle_worker_stack; - -static void wakeup_listener(void) -{ - apr_status_t rv; - - listener_may_exit = 1; - if (!idle_worker_stack) { - return; - } - if ((rv = apr_thread_mutex_lock(idle_worker_stack->mutex)) != APR_SUCCESS) { - return; - } - if ((rv = apr_thread_cond_signal(idle_worker_stack->cond)) != - APR_SUCCESS) { - return; - } - if ((rv = apr_thread_mutex_unlock(idle_worker_stack->mutex)) != APR_SUCCESS) { - return; - } - if (!listener_os_thread) { - /* XXX there is an obscure path that this doesn't handle perfectly: - * right after listener thread is created but before - * listener_os_thread is set, the first worker thread hits an - * error and starts graceful termination - */ - return; - } - /* - * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all - * platforms and wake up the listener thread since it is the only thread - * with SIGHUP unblocked, but that doesn't work on Linux - */ -#ifdef HAVE_PTHREAD_KILL - pthread_kill(*listener_os_thread, LISTENER_SIGNAL); -#else - kill(ap_my_pid, LISTENER_SIGNAL); -#endif -} - -#define ST_INIT 0 -#define ST_GRACEFUL 1 -#define ST_UNGRACEFUL 2 - -static int terminate_mode = ST_INIT; - -static void signal_threads(int mode) -{ - if (terminate_mode == mode) { - return; - } - terminate_mode = mode; - mpm_state = AP_MPMQ_STOPPING; - - /* in case we weren't called from the listener thread, wake up the - * listener thread - */ - wakeup_listener(); - - /* for ungraceful termination, let the workers exit now; - * for graceful termination, the listener thread will notify the - * workers to exit once it has stopped accepting new connections - */ - if (mode == ST_UNGRACEFUL) { - workers_may_exit = 1; - worker_stack_terminate(idle_worker_stack); - } -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = server_limit; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = thread_limit; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = min_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = max_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = ap_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) __attribute__ ((noreturn)); -static void clean_child_exit(int code) -{ - mpm_state = AP_MPMQ_STOPPING; - if (pchild) { - apr_pool_destroy(pchild); - } - exit(code); -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -static volatile int child_fatal; -ap_generation_t volatile ap_my_generation; - -/* - * 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. - */ - -static void ap_start_shutdown(void) -{ - mpm_state = AP_MPMQ_STOPPING; - 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 */ -static void ap_start_restart(int graceful) -{ - mpm_state = AP_MPMQ_STOPPING; - 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 == AP_SIG_GRACEFUL); -} - -static void set_signals(void) -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; -#endif - - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } - -#ifndef NO_USE_SIGACTION - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGINT)"); -#endif -#ifdef SIGXCPU - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXCPU, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXCPU)"); -#endif -#ifdef SIGXFSZ - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXFSZ, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXFSZ)"); -#endif -#ifdef SIGPIPE - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy - * processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(" AP_SIG_GRACEFUL_STRING ")"); -#else - if (!one_process) { -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef AP_SIG_GRACEFUL - apr_signal(AP_SIG_GRACEFUL, restart); -#endif /* AP_SIG_GRACEFUL */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) - /* XXX this is really a bad confusing obsolete name - * maybe it should be ap_mpm_process_exiting? - */ -{ - /* note: for a graceful termination, listener_may_exit will be set before - * workers_may_exit, so check listener_may_exit - */ - return listener_may_exit; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, - int my_thread_num, apr_bucket_alloc_t *bucket_alloc) -{ - conn_rec *current_conn; - long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num); - int csd; - ap_sb_handle_t *sbh; - - ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num); - apr_os_sock_get(&csd, sock); - - current_conn = ap_run_create_connection(p, ap_server_conf, sock, - conn_id, sbh, bucket_alloc); - if (current_conn) { - ap_process_connection(current_conn, sock); - ap_lingering_close(current_conn); - } -} - -/* requests_this_child has gone to zero or below. See if the admin coded - "MaxRequestsPerChild 0", and keep going in that case. Doing it this way - simplifies the hot path in worker_thread */ -static void check_infinite_requests(void) -{ - if (ap_max_requests_per_child) { - signal_threads(ST_GRACEFUL); - } - else { - /* wow! if you're executing this code, you may have set a record. - * either this child process has served over 2 billion requests, or - * you're running a threaded 2.0 on a 16 bit machine. - * - * I'll buy pizza and beers at Apachecon for the first person to do - * the former without cheating (dorking with INT_MAX, or running with - * uncommitted performance patches, for example). - * - * for the latter case, you probably deserve a beer too. Greg Ames - */ - - requests_this_child = INT_MAX; /* keep going */ - } -} - -static void unblock_signal(int sig) -{ - sigset_t sig_mask; - - sigemptyset(&sig_mask); - sigaddset(&sig_mask, sig); -#if defined(SIGPROCMASK_SETS_THREAD_MASK) - sigprocmask(SIG_UNBLOCK, &sig_mask, NULL); -#else - pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL); -#endif -} - -static void dummy_signal_handler(int sig) -{ - /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall, - * then we don't need this goofy function. - */ -} - -static void *listener_thread(apr_thread_t *thd, void * dummy) -{ - proc_info * ti = dummy; - int process_slot = ti->pid; - apr_pool_t *tpool = apr_thread_pool_get(thd); - void *csd = NULL; - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - int n; - apr_pollfd_t *pollset; - apr_status_t rv; - ap_listen_rec *lr, *last_lr = ap_listeners; - worker_wakeup_info *worker = NULL; - - free(ti); - - apr_poll_setup(&pollset, num_listensocks, tpool); - for(lr = ap_listeners ; lr != NULL ; lr = lr->next) - apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); - - /* Unblock the signal used to wake this thread up, and set a handler for - * it. - */ - unblock_signal(LISTENER_SIGNAL); - apr_signal(LISTENER_SIGNAL, dummy_signal_handler); - - /* TODO: Switch to a system where threads reuse the results from earlier - poll calls - manoj */ - while (1) { - /* TODO: requests_this_child should be synchronized - aaron */ - if (requests_this_child <= 0) { - check_infinite_requests(); - } - if (listener_may_exit) break; - - if (worker == NULL) { - rv = worker_stack_pop(idle_worker_stack, &worker); - if (APR_STATUS_IS_EOF(rv)) { - break; - } - else if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "worker_stack_pop failed"); - break; - } - ptrans = worker->pool; - } - AP_DEBUG_ASSERT(worker->state == WORKER_IDLE); - - if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (listener_may_exit) { - break; - } - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_lock failed. Attempting to shutdown " - "process gracefully."); - signal_threads(ST_GRACEFUL); - break; /* skip the lock release */ - } - - if (!APR_O_NONBLOCK_INHERITED && !ap_listeners->next) { - /* Only one listener, so skip the poll */ - lr = ap_listeners; - } - else { - while (!listener_may_exit) { - apr_status_t ret; - apr_int16_t event; - - ret = apr_poll(pollset, num_listensocks, &n, -1); - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - - /* apr_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - signal_threads(ST_GRACEFUL); - } - - if (listener_may_exit) break; - - /* find a listener */ - lr = last_lr; - do { - lr = lr->next; - if (lr == NULL) { - lr = ap_listeners; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, lr->sd, pollset); - if (event & APR_POLLIN) { - last_lr = lr; - goto got_fd; - } - } while (lr != last_lr); - } - } - got_fd: - if (!listener_may_exit) { - rv = lr->accept_func(&csd, lr, ptrans); - /* later we trash rv and rely on csd to indicate success/failure */ - AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd); - - if (rv == APR_EGENERAL) { - /* E[NM]FILE, ENOMEM, etc */ - resource_shortage = 1; - signal_threads(ST_GRACEFUL); - } - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (listener_may_exit) { - break; - } - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - } - if (csd != NULL) { - /* Wake up the sleeping worker. */ - apr_thread_mutex_lock(worker->mutex); - worker->csd = (apr_socket_t *)csd; - worker->state = WORKER_BUSY; - /* Posix allows us to signal this condition without - * owning the associated mutex, but in that case it can - * not guarantee predictable scheduling. See - * _UNIX Network Programming: Interprocess Communication_ - * by W. Richard Stevens, Vol 2, 2nd Ed, pp. 170-171. */ - apr_thread_cond_signal(worker->cond); - apr_thread_mutex_unlock(worker->mutex); - worker = NULL; - } - } - else { - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - } - break; - } - } - - workers_may_exit = 1; - if (worker) { - apr_thread_mutex_lock(worker->mutex); - worker->state = WORKER_TERMINATED; - /* Posix allows us to signal this condition without - * owning the associated mutex, but in that case it can - * not guarantee predictable scheduling. See - * _UNIX Network Programming: Interprocess Communication_ - * by W. Richard Stevens, Vol 2, 2nd Ed, pp. 170-171. */ - apr_thread_cond_signal(worker->cond); - apr_thread_mutex_unlock(worker->mutex); - } - worker_stack_terminate(idle_worker_stack); - dying = 1; - ap_scoreboard_image->parent[process_slot].quiescing = 1; - - /* wake up the main thread */ - kill(ap_my_pid, SIGTERM); - - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -/* XXX For ungraceful termination/restart, we definitely don't want to - * wait for active connections to finish but we may want to wait - * for idle workers to get out of the queue code and release mutexes, - * since those mutexes are cleaned up pretty soon and some systems - * may not react favorably (i.e., segfault) if operations are attempted - * on cleaned-up mutexes. - */ -static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy) -{ - proc_info * ti = dummy; - int process_slot = ti->pid; - int thread_slot = ti->tid; - apr_bucket_alloc_t *bucket_alloc; - apr_pool_t *tpool = apr_thread_pool_get(thd); - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_allocator_t *allocator; - apr_status_t rv; - worker_wakeup_info *wakeup; - - free(ti); - - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL); - - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - /* XXX: why is ptrans's parent not tpool? --jcw 08/2003 */ - apr_pool_create_ex(&ptrans, NULL, NULL, allocator); - apr_allocator_owner_set(allocator, ptrans); - bucket_alloc = apr_bucket_alloc_create_ex(allocator); - - wakeup = (worker_wakeup_info *)apr_palloc(tpool, sizeof(*wakeup)); - wakeup->pool = ptrans; - if ((rv = apr_thread_cond_create(&wakeup->cond, tpool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_thread_cond_create failed. Attempting to shutdown " - "process gracefully."); - signal_threads(ST_GRACEFUL); - apr_thread_exit(thd, rv); - } - if ((rv = apr_thread_mutex_create(&wakeup->mutex, APR_THREAD_MUTEX_DEFAULT, - tpool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_thread_mutex_create failed. Attempting to shutdown " - "process gracefully."); - signal_threads(ST_GRACEFUL); - apr_thread_exit(thd, rv); - } - - while (!workers_may_exit) { - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL); - rv = worker_stack_wait(idle_worker_stack, wakeup); - if (APR_STATUS_IS_EOF(rv)) { - break; /* The queue has been terminated. */ - } - else if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "worker_stack_wait failed"); - break; /* Treat all other errors as fatal. */ - } - else if (wakeup->state == WORKER_TERMINATED) { - break; /* They told us to quit. */ - } - AP_DEBUG_ASSERT(wakeup->state != WORKER_IDLE); - process_socket(ptrans, wakeup->csd, - process_slot, thread_slot, bucket_alloc); - requests_this_child--; /* FIXME: should be synchronized - aaron */ - apr_pool_clear(ptrans); - } - - ap_update_child_status_from_indexes(process_slot, thread_slot, - (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL); - - apr_bucket_alloc_destroy(bucket_alloc); - - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - return 1; - } - return 0; -} - -static void create_listener_thread(thread_starter *ts) -{ - int my_child_num = ts->child_num_arg; - apr_threadattr_t *thread_attr = ts->threadattr; - proc_info *my_info; - apr_status_t rv; - - my_info = (proc_info *)malloc(sizeof(proc_info)); - my_info->pid = my_child_num; - my_info->tid = -1; /* listener thread doesn't have a thread slot */ - my_info->sd = 0; - rv = apr_thread_create(&ts->listener, thread_attr, listener_thread, - my_info, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create listener 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 if we exit. - * XXX Jeff doesn't see how Apache is going to try to fork again since - * the exit code is APEXIT_CHILDFATAL - */ - apr_sleep(10 * APR_USEC_PER_SEC); - clean_child_exit(APEXIT_CHILDFATAL); - } - apr_os_thread_get(&listener_os_thread, ts->listener); -} - -/* XXX under some circumstances not understood, children can get stuck - * in start_threads forever trying to take over slots which will - * never be cleaned up; for now there is an APLOG_DEBUG message issued - * every so often when this condition occurs - */ -static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) -{ - thread_starter *ts = dummy; - apr_thread_t **threads = ts->threads; - apr_threadattr_t *thread_attr = ts->threadattr; - int child_num_arg = ts->child_num_arg; - int my_child_num = child_num_arg; - proc_info *my_info; - apr_status_t rv; - int i; - int threads_created = 0; - int loops; - int prev_threads_created; - - idle_worker_stack = worker_stack_create(pchild, ap_threads_per_child); - if (idle_worker_stack == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, - "worker_stack_create() failed"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - loops = prev_threads_created = 0; - while (1) { - /* ap_threads_per_child does not include the listener thread */ - for (i = 0; i < ap_threads_per_child; i++) { - int status = ap_scoreboard_image->servers[child_num_arg][i].status; - - if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { - continue; - } - - 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->pid = my_child_num; - my_info->tid = i; - my_info->sd = 0; - - /* We are creating threads right now */ - ap_update_child_status_from_indexes(my_child_num, i, - SERVER_STARTING, NULL); - /* We let each thread update its own scoreboard entry. This is - * done because it lets us deal with tid better. - */ - rv = apr_thread_create(&threads[i], thread_attr, - worker_thread, my_info, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker 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 if we exit. */ - apr_sleep(10 * APR_USEC_PER_SEC); - clean_child_exit(APEXIT_CHILDFATAL); - } - threads_created++; - if (threads_created == 1) { - /* now that we have a worker thread, it makes sense to create - * a listener thread (we don't want a listener without a worker!) - */ - create_listener_thread(ts); - } - } - if (start_thread_may_exit || threads_created == ap_threads_per_child) { - break; - } - /* wait for previous generation to clean up an entry */ - apr_sleep(1 * APR_USEC_PER_SEC); - ++loops; - if (loops % 120 == 0) { /* every couple of minutes */ - if (prev_threads_created == threads_created) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "child %" APR_PID_T_FMT " isn't taking over " - "slots very quickly (%d of %d)", - ap_my_pid, threads_created, ap_threads_per_child); - } - prev_threads_created = threads_created; - } - } - - /* What state should this child_main process be listed as in the - * scoreboard...? - * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, - * (request_rec *) NULL); - * - * This state should be listed separately in the scoreboard, in some kind - * of process_status, not mixed in with the worker threads' status. - * "life_status" is almost right, but it's in the worker's structure, and - * the name could be clearer. gla - */ - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -static void join_workers(apr_thread_t *listener, apr_thread_t **threads) -{ - int i; - apr_status_t rv, thread_rv; - - if (listener) { - int iter; - - /* deal with a rare timing window which affects waking up the - * listener thread... if the signal sent to the listener thread - * is delivered between the time it verifies that the - * listener_may_exit flag is clear and the time it enters a - * blocking syscall, the signal didn't do any good... work around - * that by sleeping briefly and sending it again - */ - - iter = 0; - while (iter < 10 && -#ifdef HAVE_PTHREAD_KILL - pthread_kill(*listener_os_thread, 0) -#else - kill(ap_my_pid, 0) -#endif - == 0) { - /* listener not dead yet */ - apr_sleep(APR_USEC_PER_SEC / 2); - wakeup_listener(); - ++iter; - } - if (iter >= 10) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "the listener thread didn't exit"); - } - else { - rv = apr_thread_join(&thread_rv, listener); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join listener thread"); - } - } - } - - for (i = 0; i < ap_threads_per_child; i++) { - if (threads[i]) { /* if we ever created this thread */ - rv = apr_thread_join(&thread_rv, threads[i]); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join worker " - "thread %d", - i); - } - } - } -} - -static void join_start_thread(apr_thread_t *start_thread_id) -{ - apr_status_t rv, thread_rv; - - start_thread_may_exit = 1; /* tell it to give up in case it is still - * trying to take over slots from a - * previous generation - */ - rv = apr_thread_join(&thread_rv, start_thread_id); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join the start " - "thread"); - } -} - -static void child_main(int child_num_arg) -{ - apr_thread_t **threads; - apr_status_t rv; - thread_starter *ts; - apr_threadattr_t *thread_attr; - apr_thread_t *start_thread_id; - - mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this - * child initializes - */ - ap_my_pid = getpid(); - ap_fatal_signal_child_setup(ap_server_conf); - apr_pool_create(&pchild, pconf); - - /*stuff to do before we switch id's, so we have permissions.*/ - ap_reopen_scoreboard(pchild, NULL, 0); - - rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, - pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (unixd_setup_child()) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /* done with init critical section */ - - /* Just use the standard apr_setup_signal_thread to block all signals - * from being received. The child processes no longer use signals for - * any communication with the parent process. - */ - rv = apr_setup_signal_thread(); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize signal thread"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (ap_max_requests_per_child) { - requests_this_child = ap_max_requests_per_child; - } - else { - /* coding a value of zero means infinity */ - requests_this_child = INT_MAX; - } - - /* Setup worker threads */ - - /* clear the storage; we may not create all our threads immediately, - * and we want a 0 entry to indicate a thread which was not created - */ - threads = (apr_thread_t **)calloc(1, - sizeof(apr_thread_t *) * ap_threads_per_child); - if (threads == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, - "malloc: out of memory"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts)); - - apr_threadattr_create(&thread_attr, pchild); - /* 0 means PTHREAD_CREATE_JOINABLE */ - apr_threadattr_detach_set(thread_attr, 0); - - ts->threads = threads; - ts->listener = NULL; - ts->child_num_arg = child_num_arg; - ts->threadattr = thread_attr; - - rv = apr_thread_create(&start_thread_id, thread_attr, start_threads, - ts, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker 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 if we exit. */ - apr_sleep(10 * APR_USEC_PER_SEC); - clean_child_exit(APEXIT_CHILDFATAL); - } - - mpm_state = AP_MPMQ_RUNNING; - - /* If we are only running in one_process mode, we will want to - * still handle signals. */ - if (one_process) { - /* Block until we get a terminating signal. */ - apr_signal_thread(check_signal); - /* make sure the start thread has finished; signal_threads() - * and join_workers() depend on that - */ - /* XXX join_start_thread() won't be awakened if one of our - * threads encounters a critical error and attempts to - * shutdown this child - */ - join_start_thread(start_thread_id); - signal_threads(ST_UNGRACEFUL); /* helps us terminate a little more - * quickly than the dispatch of the signal thread - * beats the Pipe of Death and the browsers - */ - /* A terminating signal was received. Now join each of the - * workers to clean them up. - * If the worker already exited, then the join frees - * their resources and returns. - * If the worker hasn't exited, then this blocks until - * they have (then cleans up). - */ - join_workers(ts->listener, threads); - } - else { /* !one_process */ - /* remove SIGTERM from the set of blocked signals... if one of - * the other threads in the process needs to take us down - * (e.g., for MaxRequestsPerChild) it will send us SIGTERM - */ - unblock_signal(SIGTERM); - apr_signal(SIGTERM, dummy_signal_handler); - /* Watch for any messages from the parent over the POD */ - while (1) { - rv = ap_mpm_pod_check(pod); - if (rv == AP_NORESTART) { - /* see if termination was triggered while we slept */ - switch(terminate_mode) { - case ST_GRACEFUL: - rv = AP_GRACEFUL; - break; - case ST_UNGRACEFUL: - rv = AP_RESTART; - break; - } - } - if (rv == AP_GRACEFUL || rv == AP_RESTART) { - /* make sure the start thread has finished; - * signal_threads() and join_workers depend on that - */ - join_start_thread(start_thread_id); - signal_threads(rv == AP_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); - break; - } - } - - if (rv == AP_GRACEFUL) { - /* A terminating signal was received. Now join each of the - * workers to clean them up. - * If the worker already exited, then the join frees - * their resources and returns. - * If the worker hasn't exited, then this blocks until - * they have (then cleans up). - */ - join_workers(ts->listener, threads); - } - } - - free(threads); - - clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_scoreboard_image->parent[slot].pid = getpid(); - child_main(slot); - } - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "fork: Unable to fork new process"); - - /* fork didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL); - - /* 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. */ - apr_sleep(10 * APR_USEC_PER_SEC); - - return -1; - } - - if (!pid) { -#ifdef HAVE_BINDPROCESSOR - /* By default, AIX binds to a single processor. This bit unbinds - * children which will then bind to another CPU. - */ - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, - ap_server_conf, - "processor unbind failed %d", status); -#endif - RAISE_SIGSTOP(MAKE_CHILD); - - apr_signal(SIGTERM, just_die); - child_main(slot); - - clean_child_exit(0); - } - /* else */ - ap_scoreboard_image->parent[slot].quiescing = 0; - ap_scoreboard_image->parent[slot].pid = pid; - return 0; -} - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->parent[i].pid != 0) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * idle_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 idle_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, j; - int idle_thread_count; - worker_score *ws; - process_score *ps; - int free_length; - int totally_free_length = 0; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - - /* initialize the free_list */ - free_length = 0; - - idle_thread_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - for (i = 0; i < ap_daemons_limit; ++i) { - /* Initialization to satisfy the compiler. It doesn't know - * that ap_threads_per_child is always > 0 */ - int status = SERVER_DEAD; - int any_dying_threads = 0; - int any_dead_threads = 0; - int all_dead_threads = 1; - - if (i >= ap_max_daemons_limit && totally_free_length == idle_spawn_rate) - break; - ps = &ap_scoreboard_image->parent[i]; - for (j = 0; j < ap_threads_per_child; j++) { - ws = &ap_scoreboard_image->servers[i][j]; - status = ws->status; - - /* XXX any_dying_threads is probably no longer needed GLA */ - any_dying_threads = any_dying_threads || - (status == SERVER_GRACEFUL); - any_dead_threads = any_dead_threads || (status == SERVER_DEAD); - all_dead_threads = all_dead_threads && - (status == SERVER_DEAD || - status == SERVER_GRACEFUL); - - /* We consider a starting server as idle because we started it - * at least a cycle ago, and if it still hasn't finished starting - * then we're just going to swamp things worse by forking more. - * So we hopefully won't need to fork more if we count it. - * This depends on the ordering of SERVER_READY and SERVER_STARTING. - */ - if (status <= SERVER_READY && status != SERVER_DEAD && - !ps->quiescing && - ps->generation == ap_my_generation && - /* XXX the following shouldn't be necessary if we clean up - * properly after seg faults, but we're not yet GLA - */ - ps->pid != 0) { - ++idle_thread_count; - } - } - if (any_dead_threads && totally_free_length < idle_spawn_rate - && (!ps->pid /* no process in the slot */ - || ps->quiescing)) { /* or at least one is going away */ - if (all_dead_threads) { - /* great! we prefer these, because the new process can - * start more threads sooner. So prioritize this slot - * by putting it ahead of any slots with active threads. - * - * first, make room by moving a slot that's potentially still - * in use to the end of the array - */ - free_slots[free_length] = free_slots[totally_free_length]; - free_slots[totally_free_length++] = i; - } - else { - /* slot is still in use - back of the bus - */ - free_slots[free_length] = i; - } - ++free_length; - } - /* XXX if (!ps->quiescing) is probably more reliable GLA */ - if (!any_dying_threads) { - last_non_dead = i; - ++total_non_dead; - } - } - ap_max_daemons_limit = last_non_dead + 1; - - if (idle_thread_count > max_spare_threads) { - /* Kill off one child */ - ap_mpm_pod_signal(pod, TRUE); - idle_spawn_rate = 1; - } - else if (idle_thread_count < min_spare_threads) { - /* terminate the free list */ - if (free_length == 0) { - /* only report this condition once */ - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - ap_server_conf, - "server reached MaxClients setting, consider" - " raising the MaxClients setting"); - reported = 1; - } - idle_spawn_rate = 1; - } - else { - if (free_length > idle_spawn_rate) { - free_length = idle_spawn_rate; - } - if (idle_spawn_rate >= 8) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - ap_server_conf, - "server seems busy, (you may need " - "to increase StartServers, ThreadsPerChild " - "or Min/MaxSpareThreads), " - "spawning %d children, there are around %d idle " - "threads, and %d total children", free_length, - idle_thread_count, total_non_dead); - } - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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 (idle_spawn_rate < MAX_SPAWN_RATE) { - idle_spawn_rate *= 2; - } - } - } - else { - idle_spawn_rate = 1; - } -} - -static void server_main_loop(int remaining_children_to_start) -{ - int child_slot; - apr_exit_why_e exitwhy; - int status, processed_status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); - - if (pid.pid != -1) { - processed_status = ap_process_child_status(&pid, exitwhy, status); - if (processed_status == APEXIT_CHILDFATAL) { - shutdown_pending = 1; - child_fatal = 1; - return; - } - /* non-fatal death... note that it's gone in the scoreboard. */ - child_slot = find_child_by_pid(&pid); - if (child_slot >= 0) { - for (i = 0; i < ap_threads_per_child; i++) - ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD, - (request_rec *) NULL); - - ap_scoreboard_image->parent[child_slot].pid = 0; - ap_scoreboard_image->parent[child_slot].quiescing = 0; - if (processed_status == APEXIT_CHILDSICK) { - /* resource shortage, minimize the fork rate */ - idle_spawn_rate = 1; - } - else if (remaining_children_to_start - && child_slot < ap_daemons_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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_WARNING, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)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_children_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_children(remaining_children_to_start); - remaining_children_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(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - apr_status_t rv; - - ap_log_pid(pconf, ap_pid_fname); - - first_server_limit = server_limit; - first_thread_limit = thread_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit or ThreadLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - - /* Initialize cross-process accept lock */ - ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, - ap_server_root_relative(_pconf, ap_lock_fname), - ap_my_pid); - - rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname, - ap_accept_lock_mech, _pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create accept lock"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - -#if APR_USE_SYSVSEM_SERIALIZE - if (ap_accept_lock_mech == APR_LOCK_DEFAULT || - ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#else - if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#endif - rv = unixd_set_proc_mutex_perms(accept_mutex); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't set permissions on cross-process lock; " - "check User and Group directives"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - } - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - /* fix the generation number in the global score; we just got a new, - * cleared scoreboard - */ - ap_scoreboard_image->global->running_generation = ap_my_generation; - } - - set_signals(); - /* Don't thrash... */ - if (max_spare_threads < min_spare_threads + ap_threads_per_child) - max_spare_threads = min_spare_threads + ap_threads_per_child; - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least daemons_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_children_to_start = ap_daemons_to_start; - if (remaining_children_to_start > ap_daemons_limit) { - remaining_children_to_start = ap_daemons_limit; - } - if (!is_graceful) { - startup_children(remaining_children_to_start); - remaining_children_to_start = 0; - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(accept_mutex), - apr_proc_mutex_defname()); -#endif - restart_pending = shutdown_pending = 0; - mpm_state = AP_MPMQ_RUNNING; - - server_main_loop(remaining_children_to_start); - mpm_state = AP_MPMQ_STOPPING; - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - * (By "gracefully" we don't mean graceful in the same sense as - * "apachectl graceful" where we allow old connections to finish.) - */ - ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE); - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - - if (!child_fatal) { - /* 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_INFO, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, - ap_server_conf, "caught SIGTERM, shutting down"); - } - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); - /* wake up the children...time to die. But we'll have more soon */ - ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE); - - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - } - 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. - */ - ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE); - - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - return 0; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - apr_status_t rv; - ap_listen_rec *lr; - - pconf = p; - ap_server_conf = s; - - if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - -#if APR_O_NONBLOCK_INHERITED - for(lr = ap_listeners ; lr != NULL ; lr = lr->next) { - apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, 1); - } -#endif /* APR_O_NONBLOCK_INHERITED */ - - if (!one_process) { - if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); - return DONE; - } - } - return OK; -} - -static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach, debug, foreground; - ap_directive_t *pdir; - ap_directive_t *max_clients = NULL; - apr_status_t rv; - - mpm_state = AP_MPMQ_STARTING; - - /* make sure that "ThreadsPerChild" gets set before "MaxClients" */ - for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) { - if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) { - if (!max_clients) { - break; /* we're in the clear, got ThreadsPerChild first */ - } - else { - /* now to swap the data */ - ap_directive_t temp; - - temp.directive = pdir->directive; - temp.args = pdir->args; - /* Make sure you don't change 'next', or you may get loops! */ - /* XXX: first_child, parent, and data can never be set - * for these directives, right? -aaron */ - temp.filename = pdir->filename; - temp.line_num = pdir->line_num; - - pdir->directive = max_clients->directive; - pdir->args = max_clients->args; - pdir->filename = max_clients->filename; - pdir->line_num = max_clients->line_num; - - max_clients->directive = temp.directive; - max_clients->args = temp.args; - max_clients->filename = temp.filename; - max_clients->line_num = temp.line_num; - break; - } - } - else if (!max_clients - && strncasecmp(pdir->directive, "MaxClients", 10) == 0) { - max_clients = pdir; - } - } - - debug = ap_exists_config_define("DEBUG"); - - if (debug) { - foreground = one_process = 1; - no_detach = 0; - } - else { - one_process = ap_exists_config_define("ONE_PROCESS"); - no_detach = ap_exists_config_define("NO_DETACH"); - foreground = ap_exists_config_define("FOREGROUND"); - } - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !foreground) { - rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND - : APR_PROC_DETACH_DAEMONIZE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "apr_proc_detach failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - parent_pid = ap_my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_START_DAEMON; - min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - ap_daemons_limit = server_limit; - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static void threadpool_hooks(apr_pool_t *p) -{ - /* The worker open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - one_process = 0; - - ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); - /* we need to set the MPM state before other pre-config hooks use MPM query - * to retrieve it, so register as REALLY_FIRST - */ - ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); -} - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, - const 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, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, - const 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_max_clients (cmd_parms *cmd, void *dummy, - const char *arg) -{ - int max_clients; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - /* It is ok to use ap_threads_per_child here because we are - * sure that it gets set before MaxClients in the pre_config stage. */ - max_clients = atoi(arg); - if (max_clients < ap_threads_per_child) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) must be at least as large", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " large as ThreadsPerChild (%d). Automatically", - ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " increasing MaxClients to %d.", - ap_threads_per_child); - max_clients = ap_threads_per_child; - } - ap_daemons_limit = max_clients / ap_threads_per_child; - if ((max_clients > 0) && (max_clients % ap_threads_per_child)) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) is not an integer multiple", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " of ThreadsPerChild (%d), lowering MaxClients to %d", - ap_threads_per_child, - ap_daemons_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " for a maximum of %d child processes,", - ap_daemons_limit); - max_clients = ap_daemons_limit * ap_threads_per_child; - } - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d would require %d servers,", - max_clients, ap_daemons_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " and would exceed the ServerLimit value of %d.", - server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " Automatically lowering MaxClients to %d. To increase,", - server_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " please see the ServerLimit directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, - const 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 > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "threads, lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_server_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } - return NULL; -} - -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_thread_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d servers,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } - return NULL; -} - -static const command_rec threadpool_cmds[] = { -UNIX_DAEMON_COMMANDS, -LISTEN_COMMANDS, -AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle children"), -AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, - "Maximum number of children alive at the same time"), -AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, - "Maximum value of MaxClients for this run of Apache"), -AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, - "Maximum worker threads in a server for this run of Apache"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_threadpool_module = { - MPM20_MODULE_STUFF, - ap_mpm_rewrite_args, /* 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 */ - threadpool_cmds, /* command apr_table_t */ - threadpool_hooks /* register_hooks */ -}; - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/monitoring-services.txt b/rubbos/app/httpd-2.0.64/server/mpm/monitoring-services.txt deleted file mode 100644 index 24665890..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/monitoring-services.txt +++ /dev/null @@ -1,94 +0,0 @@ -From: William A. Rowe, Jr. -Date: June 7th '00 -Subject: service monitoring in Apache 1.3.13 - -The concept for a taskbar monitor has been thrown around -for a very long while. 1.3.13 introduced Win9x services, -and that added fuel to the mix. Here are some sideband -observations I've made for other developers... - -About Apache as a console, don't start Apache hidden without -any command line arguments if you want to launch it yourself -in a hidden window (it will do the classic test for -AllocConsole/FreeConsole)... drop in some arguments such as -the -f or -r option and it will fly without thinking it is a -service under 9x and NT. - -Rule two, don't use --ntservice as an argument, ever. Only -the Windows NT Service Control Manager is allowed to pass that -flag, and only that flag, when it runs Apache.exe. Do use ---ntservice as the sole argument to the executable name if -you are installing an Apache NT service yourself. - -Rule three, use -k start and -n name when maintaining the -HKLM/Software/Microsoft/Windows/CurrentVersion/RunServices -list, since there is no other way for Apache to know what -the service is named :) And look at any 9x installed service's -RunServices entry in the registry for the start service semantic. - -Rule four, use the WinNT Service Control Manager exclusively -for starting, stopping and restarting Apache as an NT service. -The restart signal is the value 128, as documented in service.h -and service.c - this will continue to work in Apache 2.0. If -it fails, you are handling an older version (pre 1.3.13) of -Apache, and need to stop and then start the service instead. - -Rule five, use the legacy pid-named events to signal Win9x -service Apache to restart and stop the service. But don't -bother looking for httpd.pid files... you can get the pid -right from the hidden service control window. Apache 1.3.13 -and 2.x create a hidden window named for the name of the -service (without the spaces), with a window class of -"ApacheWin95ServiceMonitor", so can use FindWindow to track -down running Win9x services. See the service.c code for how -I accomplished this pretty simply in the -k stop/-k restart -handler. - -Taskbar Monitor App -------------------- - -Basic requirements: a C code application using strictly the -Win32 API, and not MFC or other Win32 frameworks. Could use -the service.c module to share some basic functions. That -module could be extended in Apache 2.0 to make this all easier. - -I think we are looking for an external app that simply acts -as a monitor or allows a stopped service to be started. If -the user logs off, we loose the monitor app, but installed as -a shortcut in the Start group or in the registry key -HKLM/Software/Microsoft/Windows/CurrentVersion/Run -we will be just fine. I'd like to see the monitor run only -one instance to monitor all running services, for memory -and resource conservation. - -I was thinking that the hover/iconbar title would tell them -"Test service is running", or "Test service is stopped". -If they left click, they could stop or restart, or simply -start if it is stopped. There could be a preference that -each service doesn't get it's own individual task icon unless -it is running, if it is a manual start service (or missing -from the RunServices list, which is the equivilant under 9x). - -If a specific service is set to Auto start or is in the -RunServices Win9x registry key, we must show them the stopped -icon, of course. We might also keep the icon for any running -service that stops abruptly. But there could be a 'single -icon' option for the taskbar icon monitor that says show only -a single status icon, for simplicity if the administrator runs -many Apache services. - -But I was hoping that any right click would provide a menu -of all Apache services with their status. e.g. - Test service is stopped - Apache_2 service is running - MyWeb service is running -and each would do the logical submenu, same as if that -specific taskbar icon were left clicked, offering to start or -offering to stop or restart the server, as appropriate. - -Finally, to identify all installed Apache services, just query -the registry key HKLM\SYSTEM\CurrentControlSet\Services for any -key that has the ImagePath value of "...\Apache.exe"... (quotes -are significant here, if the leading quote is ommitted the -entire string ends with the text \Apache.exe - based on Apache's -own service installer in every released version.) diff --git a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/Makefile.in deleted file mode 100644 index 38e598ed..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libmpmt_os2.la -LTLIBRARY_SOURCES = mpmt_os2.c mpmt_os2_child.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/config5.m4 b/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/config5.m4 deleted file mode 100644 index b27c296d..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/config5.m4 +++ /dev/null @@ -1,5 +0,0 @@ -if test "$MPM_NAME" = "mpmt_os2" ; then - AC_CACHE_SAVE - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) - APR_ADDTO(CFLAGS,-Zmt) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpm.h deleted file mode 100644 index 15f341dd..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpm.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_MPMT_OS2_H -#define APACHE_MPM_MPMT_OS2_H - -#define MPMT_OS2_MPM - -#include "httpd.h" -#include "mpm_default.h" -#include "scoreboard.h" - -#define MPM_NAME "MPMT_OS2" - -extern server_rec *ap_server_conf; -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK -#define AP_MPM_WANT_SET_MAX_MEM_FREE - -#endif /* APACHE_MPM_MPMT_OS2_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpm_default.h deleted file mode 100644 index d45b2ce2..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpm_default.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* Number of servers processes to spawn off by default - */ -#ifndef DEFAULT_START_DAEMON -#define DEFAULT_START_DAEMON 2 -#endif - -/* Maximum number of *free* server threads --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_SPARE_THREAD -#define DEFAULT_MAX_SPARE_THREAD 10 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_SPARE_THREAD -#define DEFAULT_MIN_SPARE_THREAD 5 -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpmt_os2.c b/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpmt_os2.c deleted file mode 100644 index 2c7f57bf..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpmt_os2.c +++ /dev/null @@ -1,577 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Multi-process, multi-threaded MPM for OS/2 - * - * Server consists of - * - a main, parent process - * - a small, static number of child processes - * - * The parent process's job is to manage the child processes. This involves - * spawning children as required to ensure there are always ap_daemons_to_start - * processes accepting connections. - * - * Each child process consists of a a pool of worker threads and a - * main thread that accepts connections & passes them to the workers via - * a work queue. The worker thread pool is dynamic, managed by a maintanence - * thread so that the number of idle threads is kept between - * min_spare_threads & max_spare_threads. - * - */ - -/* - Todo list - - Enforce MaxClients somehow -*/ -#define CORE_PRIVATE -#define INCL_NOPMAPI -#define INCL_DOS -#define INCL_DOSERRORS - -#include "ap_config.h" -#include "httpd.h" -#include "mpm_default.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "mpm.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "apr_portable.h" -#include "mpm_common.h" -#include "apr_strings.h" -#include <os2.h> -#include <process.h> - -/* We don't need many processes, - * they're only for redundancy in the event of a crash - */ -#define HARD_SERVER_LIMIT 10 - -/* Limit on the total number of threads per process - */ -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 256 -#endif - -server_rec *ap_server_conf; -static apr_pool_t *pconf = NULL; /* Pool for config stuff */ -static const char *ap_pid_fname=NULL; - -/* Config globals */ -static int one_process = 0; -static int ap_daemons_to_start = 0; -static int ap_thread_limit = 0; -static int ap_max_requests_per_child = 0; -int ap_min_spare_threads = 0; -int ap_max_spare_threads = 0; - -/* Keep track of a few interesting statistics */ -int ap_max_daemons_limit = -1; - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful = 0; -ap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */ -static int is_parent_process=TRUE; -HMTX ap_mpm_accept_mutex = 0; - -/* An array of these is stored in a shared memory area for passing - * sockets from the parent to child processes - */ -typedef struct { - struct sockaddr_in name; - apr_os_sock_t listen_fd; -} listen_socket_t; - -typedef struct { - HMTX accept_mutex; - listen_socket_t listeners[1]; -} parent_info_t; - -static char master_main(); -static void spawn_child(int slot); -void ap_mpm_child_main(apr_pool_t *pconf); -static void set_signals(); - - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) -{ - char *listener_shm_name; - parent_info_t *parent_info; - ULONG rc; - pconf = _pconf; - ap_server_conf = s; - restart_pending = 0; - - DosSetMaxFH(ap_thread_limit * 2); - listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getppid()); - rc = DosGetNamedSharedMem((PPVOID)&parent_info, listener_shm_name, PAG_READ); - is_parent_process = rc != 0; - ap_scoreboard_fname = apr_psprintf(pconf, "/sharemem/httpd/scoreboard.%d", is_parent_process ? getpid() : getppid()); - - if (rc == 0) { - /* Child process */ - ap_listen_rec *lr; - int num_listeners = 0; - - ap_mpm_accept_mutex = parent_info->accept_mutex; - - /* Set up a default listener if necessary */ - if (ap_listeners == NULL) { - ap_listen_rec *lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec)); - ap_listeners = lr; - apr_sockaddr_info_get(&lr->bind_addr, "0.0.0.0", APR_UNSPEC, - DEFAULT_HTTP_PORT, 0, s->process->pool); - apr_socket_create(&lr->sd, lr->bind_addr->family, - SOCK_STREAM, s->process->pool); - } - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_sockaddr_t *sa; - apr_os_sock_put(&lr->sd, &parent_info->listeners[num_listeners].listen_fd, pconf); - apr_socket_addr_get(&sa, APR_LOCAL, lr->sd); - num_listeners++; - } - - DosFreeMem(parent_info); - - /* Do the work */ - ap_mpm_child_main(pconf); - - /* Outta here */ - return 1; - } - else { - /* Parent process */ - char restart; - is_parent_process = TRUE; - - if (ap_setup_listeners(ap_server_conf) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return 1; - } - - ap_log_pid(pconf, ap_pid_fname); - - restart = master_main(); - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - - if (!restart) { - const char *pidfile = ap_server_root_relative(pconf, ap_pid_fname); - - if (pidfile != NULL && remove(pidfile) == 0) { - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, - ap_server_conf, "removed PID file %s (pid=%d)", - pidfile, getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - return 1; - } - } /* Parent process */ - - return 0; /* Restart */ -} - - - -/* Main processing of the parent process - * returns TRUE if restarting - */ -static char master_main() -{ - server_rec *s = ap_server_conf; - ap_listen_rec *lr; - parent_info_t *parent_info; - char *listener_shm_name; - int listener_num, num_listeners, slot; - ULONG rc; - - printf("%s \n", ap_get_server_version()); - set_signals(); - - if (ap_setup_listeners(ap_server_conf) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return FALSE; - } - - /* Allocate a shared memory block for the array of listeners */ - for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) { - num_listeners++; - } - - listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getpid()); - rc = DosAllocSharedMem((PPVOID)&parent_info, listener_shm_name, - sizeof(parent_info_t) + num_listeners * sizeof(listen_socket_t), - PAG_READ|PAG_WRITE|PAG_COMMIT); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s, - "failure allocating shared memory, shutting down"); - return FALSE; - } - - /* Store the listener sockets in the shared memory area for our children to see */ - for (listener_num = 0, lr = ap_listeners; lr; lr = lr->next, listener_num++) { - apr_os_sock_get(&parent_info->listeners[listener_num].listen_fd, lr->sd); - } - - /* Create mutex to prevent multiple child processes from detecting - * a connection with apr_poll() - */ - - rc = DosCreateMutexSem(NULL, &ap_mpm_accept_mutex, DC_SEM_SHARED, FALSE); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s, - "failure creating accept mutex, shutting down"); - return FALSE; - } - - parent_info->accept_mutex = ap_mpm_accept_mutex; - - /* Allocate shared memory for scoreboard */ - if (ap_scoreboard_image == NULL) { - void *sb_mem; - rc = DosAllocSharedMem(&sb_mem, ap_scoreboard_fname, - ap_calc_scoreboard_size(), - PAG_COMMIT|PAG_READ|PAG_WRITE); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "unable to allocate shared memory for scoreboard , exiting"); - return FALSE; - } - - ap_init_scoreboard(sb_mem); - } - - ap_scoreboard_image->global->restart_time = apr_time_now(); - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(accept_mutex), - apr_proc_mutex_defname()); -#endif - if (one_process) { - ap_scoreboard_image->parent[0].pid = getpid(); - ap_mpm_child_main(pconf); - return FALSE; - } - - while (!restart_pending && !shutdown_pending) { - RESULTCODES proc_rc; - PID child_pid; - int active_children = 0; - - /* Count number of active children */ - for (slot=0; slot < HARD_SERVER_LIMIT; slot++) { - active_children += ap_scoreboard_image->parent[slot].pid != 0 && - !ap_scoreboard_image->parent[slot].quiescing; - } - - /* Spawn children if needed */ - for (slot=0; slot < HARD_SERVER_LIMIT && active_children < ap_daemons_to_start; slot++) { - if (ap_scoreboard_image->parent[slot].pid == 0) { - spawn_child(slot); - active_children++; - } - } - - rc = DosWaitChild(DCWA_PROCESSTREE, DCWW_NOWAIT, &proc_rc, &child_pid, 0); - - if (rc == 0) { - /* A child has terminated, remove its scoreboard entry & terminate if necessary */ - for (slot=0; ap_scoreboard_image->parent[slot].pid != child_pid && slot < HARD_SERVER_LIMIT; slot++); - - if (slot < HARD_SERVER_LIMIT) { - ap_scoreboard_image->parent[slot].pid = 0; - ap_scoreboard_image->parent[slot].quiescing = 0; - - if (proc_rc.codeTerminate == TC_EXIT) { - /* Child terminated normally, check its exit code and - * terminate server if child indicates a fatal error - */ - if (proc_rc.codeResult == APEXIT_CHILDFATAL) - break; - } - } - } else if (rc == ERROR_CHILD_NOT_COMPLETE) { - /* No child exited, lets sleep for a while.... */ - apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL); - } - } - - /* Signal children to shut down, either gracefully or immediately */ - for (slot=0; slot<HARD_SERVER_LIMIT; slot++) { - kill(ap_scoreboard_image->parent[slot].pid, is_graceful ? SIGHUP : SIGTERM); - } - - DosFreeMem(parent_info); - return restart_pending; -} - - - -static void spawn_child(int slot) -{ - PPIB ppib; - PTIB ptib; - char fail_module[100]; - char progname[CCHMAXPATH]; - RESULTCODES proc_rc; - ULONG rc; - - ap_scoreboard_image->parent[slot].generation = ap_my_generation; - DosGetInfoBlocks(&ptib, &ppib); - DosQueryModuleName(ppib->pib_hmte, sizeof(progname), progname); - rc = DosExecPgm(fail_module, sizeof(fail_module), EXEC_ASYNCRESULT, - ppib->pib_pchcmd, NULL, &proc_rc, progname); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "error spawning child, slot %d", slot); - } - - if (ap_max_daemons_limit < slot) { - ap_max_daemons_limit = slot; - } - - ap_scoreboard_image->parent[slot].pid = proc_rc.codeTerminate; -} - - - -/* Signal handling routines */ - -static void sig_term(int sig) -{ - shutdown_pending = 1; - signal(SIGTERM, SIG_DFL); -} - - - -static void sig_restart(int sig) -{ - if (sig == SIGUSR1) { - is_graceful = 1; - } - - restart_pending = 1; -} - - - -static void set_signals() -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = sig_term; - - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)"); - - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)"); - - sa.sa_handler = sig_restart; - - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGUSR1, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGUSR1)"); -} - - - -/* Enquiry functions used get MPM status info */ - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch (query_code) { - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - - - -int ap_graceful_stop_signalled(void) -{ - return is_graceful; -} - - - -/* Configuration handling stuff */ - -static int mpmt_os2_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - one_process = ap_exists_config_define("ONE_PROCESS") || - ap_exists_config_define("DEBUG"); - is_graceful = 0; - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_START_DAEMON; - ap_thread_limit = HARD_THREAD_LIMIT; - ap_pid_fname = DEFAULT_PIDLOG; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; - ap_min_spare_threads = DEFAULT_MIN_SPARE_THREAD; - ap_max_spare_threads = DEFAULT_MAX_SPARE_THREAD; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - return OK; -} - - - -static void mpmt_os2_hooks(apr_pool_t *p) -{ - ap_hook_pre_config(mpmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE); -} - - - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - - - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - - if (err != NULL) { - return err; - } - - ap_min_spare_threads = atoi(arg); - - if (ap_min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - ap_min_spare_threads = 1; - } - - return NULL; -} - - - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - - if (err != NULL) { - return err; - } - - ap_max_spare_threads = atoi(arg); - return NULL; -} - - - -static const char *ignore_cmd(cmd_parms *cmd, void *dummy, const char *arg) -{ - return NULL; -} - - - -static const command_rec mpmt_os2_cmds[] = { -LISTEN_COMMANDS, -AP_INIT_TAKE1( "StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup" ), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle children"), -AP_INIT_TAKE1("User", ignore_cmd, NULL, RSRC_CONF, - "Not applicable on this platform"), -AP_INIT_TAKE1("Group", ignore_cmd, NULL, RSRC_CONF, - "Not applicable on this platform"), -AP_INIT_TAKE1("ScoreBoardFile", ignore_cmd, NULL, RSRC_CONF, \ - "Not applicable on this platform"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_mpmt_os2_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 */ - mpmt_os2_cmds, /* command apr_table_t */ - mpmt_os2_hooks, /* register_hooks */ -}; diff --git a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpmt_os2_child.c b/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpmt_os2_child.c deleted file mode 100644 index 1b47cae0..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/mpmt_os2/mpmt_os2_child.c +++ /dev/null @@ -1,497 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define CORE_PRIVATE -#define INCL_NOPMAPI -#define INCL_DOS -#define INCL_DOSERRORS - -#include "ap_config.h" -#include "httpd.h" -#include "mpm_default.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "mpm.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "apr_portable.h" -#include "apr_poll.h" -#include "mpm_common.h" -#include "apr_strings.h" -#include <os2.h> -#include <process.h> - -/* XXXXXX move these to header file private to this MPM */ - -/* We don't need many processes, - * they're only for redundancy in the event of a crash - */ -#define HARD_SERVER_LIMIT 10 - -/* Limit on the total number of threads per process - */ -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 256 -#endif - -#define ID_FROM_CHILD_THREAD(c, t) ((c * HARD_THREAD_LIMIT) + t) - -typedef struct { - apr_pool_t *pconn; - apr_socket_t *conn_sd; -} worker_args_t; - -#define WORKTYPE_CONN 0 -#define WORKTYPE_EXIT 1 - -static apr_pool_t *pchild = NULL; -static int child_slot; -static int shutdown_pending = 0; -extern int ap_my_generation; -static int volatile is_graceful = 1; -HEV shutdown_event; /* signaled when this child is shutting down */ - -/* grab some MPM globals */ -extern int ap_min_spare_threads; -extern int ap_max_spare_threads; -extern HMTX ap_mpm_accept_mutex; - -static void worker_main(void *vpArg); -static void clean_child_exit(int code); -static void set_signals(); -static void server_maintenance(void *vpArg); - - -static void clean_child_exit(int code) -{ - if (pchild) { - apr_pool_destroy(pchild); - } - - exit(code); -} - - - -void ap_mpm_child_main(apr_pool_t *pconf) -{ - ap_listen_rec *lr = NULL; - ap_listen_rec *first_lr = NULL; - int requests_this_child = 0; - apr_socket_t *sd = ap_listeners->sd; - int nsds, rv = 0; - unsigned long ulTimes; - int my_pid = getpid(); - ULONG rc, c; - HQUEUE workq; - apr_pollfd_t *pollset; - int num_listeners; - TID server_maint_tid; - void *sb_mem; - - /* Stop Ctrl-C/Ctrl-Break signals going to child processes */ - DosSetSignalExceptionFocus(0, &ulTimes); - set_signals(); - - /* Create pool for child */ - apr_pool_create(&pchild, pconf); - - ap_run_child_init(pchild, ap_server_conf); - - /* Create an event semaphore used to trigger other threads to shutdown */ - rc = DosCreateEventSem(NULL, &shutdown_event, 0, FALSE); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "unable to create shutdown semaphore, exiting"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - /* Gain access to the scoreboard. */ - rc = DosGetNamedSharedMem(&sb_mem, ap_scoreboard_fname, - PAG_READ|PAG_WRITE); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "scoreboard not readable in child, exiting"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_calc_scoreboard_size(); - ap_init_scoreboard(sb_mem); - - /* Gain access to the accpet mutex */ - rc = DosOpenMutexSem(NULL, &ap_mpm_accept_mutex); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "accept mutex couldn't be accessed in child, exiting"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - /* Find our pid in the scoreboard so we know what slot our parent allocated us */ - for (child_slot = 0; ap_scoreboard_image->parent[child_slot].pid != my_pid && child_slot < HARD_SERVER_LIMIT; child_slot++); - - if (child_slot == HARD_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "child pid not found in scoreboard, exiting"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_my_generation = ap_scoreboard_image->parent[child_slot].generation; - memset(ap_scoreboard_image->servers[child_slot], 0, sizeof(worker_score) * HARD_THREAD_LIMIT); - - /* Set up an OS/2 queue for passing connections & termination requests - * to worker threads - */ - rc = DosCreateQueue(&workq, QUE_FIFO, apr_psprintf(pchild, "/queues/httpd/work.%d", my_pid)); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "unable to create work queue, exiting"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - /* Create initial pool of worker threads */ - for (c = 0; c < ap_min_spare_threads; c++) { -// ap_scoreboard_image->servers[child_slot][c].tid = _beginthread(worker_main, NULL, 128*1024, (void *)c); - } - - /* Start maintenance thread */ - server_maint_tid = _beginthread(server_maintenance, NULL, 32768, NULL); - - /* Set up poll */ - for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) { - num_listeners++; - } - - apr_poll_setup(&pollset, num_listeners, pchild); - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); - } - - /* Main connection accept loop */ - do { - apr_pool_t *pconn; - worker_args_t *worker_args; - - apr_pool_create(&pconn, pchild); - worker_args = apr_palloc(pconn, sizeof(worker_args_t)); - worker_args->pconn = pconn; - - if (num_listeners == 1) { - rv = apr_accept(&worker_args->conn_sd, ap_listeners->sd, pconn); - } else { - rc = DosRequestMutexSem(ap_mpm_accept_mutex, SEM_INDEFINITE_WAIT); - - if (shutdown_pending) { - DosReleaseMutexSem(ap_mpm_accept_mutex); - break; - } - - rv = APR_FROM_OS_ERROR(rc); - - if (rv == APR_SUCCESS) { - rv = apr_poll(pollset, num_listeners, &nsds, -1); - DosReleaseMutexSem(ap_mpm_accept_mutex); - } - - if (rv == APR_SUCCESS) { - if (first_lr == NULL) { - first_lr = ap_listeners; - } - - lr = first_lr; - - do { - apr_int16_t event; - - apr_poll_revents_get(&event, lr->sd, pollset); - - if (event == APR_POLLIN) { - apr_sockaddr_t *sa; - apr_port_t port; - apr_socket_addr_get(&sa, APR_LOCAL, lr->sd); - apr_sockaddr_port_get(&port, sa); - first_lr = lr->next; - break; - } - lr = lr->next; - - if (!lr) { - lr = ap_listeners; - } - } while (lr != first_lr); - - if (lr == first_lr) { - continue; - } - - sd = lr->sd; - rv = apr_accept(&worker_args->conn_sd, sd, pconn); - } - } - - if (rv != APR_SUCCESS) { - if (!APR_STATUS_IS_EINTR(rv)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "apr_accept"); - clean_child_exit(APEXIT_CHILDFATAL); - } - } else { - DosWriteQueue(workq, WORKTYPE_CONN, sizeof(worker_args_t), worker_args, 0); - requests_this_child++; - } - - if (ap_max_requests_per_child != 0 && requests_this_child >= ap_max_requests_per_child) - break; - } while (!shutdown_pending && ap_my_generation == ap_scoreboard_image->global->running_generation); - - ap_scoreboard_image->parent[child_slot].quiescing = 1; - DosPostEventSem(shutdown_event); - DosWaitThread(&server_maint_tid, DCWW_WAIT); - - if (is_graceful) { - char someleft; - - /* tell our worker threads to exit */ - for (c=0; c<HARD_THREAD_LIMIT; c++) { - if (ap_scoreboard_image->servers[child_slot][c].status != SERVER_DEAD) { - DosWriteQueue(workq, WORKTYPE_EXIT, 0, NULL, 0); - } - } - - do { - someleft = 0; - - for (c=0; c<HARD_THREAD_LIMIT; c++) { - if (ap_scoreboard_image->servers[child_slot][c].status != SERVER_DEAD) { - someleft = 1; - DosSleep(1000); - break; - } - } - } while (someleft); - } else { - DosPurgeQueue(workq); - - for (c=0; c<HARD_THREAD_LIMIT; c++) { - if (ap_scoreboard_image->servers[child_slot][c].status != SERVER_DEAD) { - DosKillThread(ap_scoreboard_image->servers[child_slot][c].tid); - } - } - } - - apr_pool_destroy(pchild); -} - - - -void add_worker() -{ - int thread_slot; - - /* Find a free thread slot */ - for (thread_slot=0; thread_slot < HARD_THREAD_LIMIT; thread_slot++) { - if (ap_scoreboard_image->servers[child_slot][thread_slot].status == SERVER_DEAD) { - ap_scoreboard_image->servers[child_slot][thread_slot].status = SERVER_STARTING; - ap_scoreboard_image->servers[child_slot][thread_slot].tid = - _beginthread(worker_main, NULL, 128*1024, (void *)thread_slot); - break; - } - } -} - - - -ULONG APIENTRY thread_exception_handler(EXCEPTIONREPORTRECORD *pReportRec, - EXCEPTIONREGISTRATIONRECORD *pRegRec, - CONTEXTRECORD *pContext, - PVOID p) -{ - int c; - - if (pReportRec->fHandlerFlags & EH_NESTED_CALL) { - return XCPT_CONTINUE_SEARCH; - } - - if (pReportRec->ExceptionNum == XCPT_ACCESS_VIOLATION || - pReportRec->ExceptionNum == XCPT_INTEGER_DIVIDE_BY_ZERO) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "caught exception in worker thread, initiating child shutdown pid=%d", getpid()); - for (c=0; c<HARD_THREAD_LIMIT; c++) { - if (ap_scoreboard_image->servers[child_slot][c].tid == _gettid()) { - ap_scoreboard_image->servers[child_slot][c].status = SERVER_DEAD; - break; - } - } - - /* Shut down process ASAP, it could be quite unhealthy & leaking resources */ - shutdown_pending = 1; - ap_scoreboard_image->parent[child_slot].quiescing = 1; - kill(getpid(), SIGHUP); - DosUnwindException(UNWIND_ALL, 0, 0); - } - - return XCPT_CONTINUE_SEARCH; -} - - - -static void worker_main(void *vpArg) -{ - long conn_id; - conn_rec *current_conn; - apr_pool_t *pconn; - apr_allocator_t *allocator; - apr_bucket_alloc_t *bucket_alloc; - worker_args_t *worker_args; - HQUEUE workq; - PID owner; - int rc; - REQUESTDATA rd; - ULONG len; - BYTE priority; - int thread_slot = (int)vpArg; - EXCEPTIONREGISTRATIONRECORD reg_rec = { NULL, thread_exception_handler }; - ap_sb_handle_t *sbh; - - /* Trap exceptions in this thread so we don't take down the whole process */ - DosSetExceptionHandler( ®_rec ); - - rc = DosOpenQueue(&owner, &workq, - apr_psprintf(pchild, "/queues/httpd/work.%d", getpid())); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "unable to open work queue, exiting"); - ap_scoreboard_image->servers[child_slot][thread_slot].tid = 0; - } - - conn_id = ID_FROM_CHILD_THREAD(child_slot, thread_slot); - ap_update_child_status_from_indexes(child_slot, thread_slot, SERVER_READY, - NULL); - - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - bucket_alloc = apr_bucket_alloc_create_ex(allocator); - - while (rc = DosReadQueue(workq, &rd, &len, (PPVOID)&worker_args, 0, DCWW_WAIT, &priority, NULLHANDLE), - rc == 0 && rd.ulData != WORKTYPE_EXIT) { - pconn = worker_args->pconn; - ap_create_sb_handle(&sbh, pconn, child_slot, thread_slot); - current_conn = ap_run_create_connection(pconn, ap_server_conf, - worker_args->conn_sd, conn_id, - sbh, bucket_alloc); - - if (current_conn) { - ap_process_connection(current_conn, worker_args->conn_sd); - ap_lingering_close(current_conn); - } - - apr_pool_destroy(pconn); - ap_update_child_status_from_indexes(child_slot, thread_slot, - SERVER_READY, NULL); - } - - ap_update_child_status_from_indexes(child_slot, thread_slot, SERVER_DEAD, - NULL); - - apr_bucket_alloc_destroy(bucket_alloc); - apr_allocator_destroy(allocator); -} - - - -static void server_maintenance(void *vpArg) -{ - int num_idle, num_needed; - ULONG num_pending = 0; - int threadnum; - HQUEUE workq; - ULONG rc; - PID owner; - - rc = DosOpenQueue(&owner, &workq, - apr_psprintf(pchild, "/queues/httpd/work.%d", getpid())); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf, - "unable to open work queue in maintenance thread"); - return; - } - - do { - for (num_idle=0, threadnum=0; threadnum < HARD_THREAD_LIMIT; threadnum++) { - num_idle += ap_scoreboard_image->servers[child_slot][threadnum].status == SERVER_READY; - } - - DosQueryQueue(workq, &num_pending); - num_needed = ap_min_spare_threads - num_idle + num_pending; - - if (num_needed > 0) { - for (threadnum=0; threadnum < num_needed; threadnum++) { - add_worker(); - } - } - - if (num_idle - num_pending > ap_max_spare_threads) { - DosWriteQueue(workq, WORKTYPE_EXIT, 0, NULL, 0); - } - } while (DosWaitEventSem(shutdown_event, 500) == ERROR_TIMEOUT); -} - - - -/* Signal handling routines */ - -static void sig_term(int sig) -{ - shutdown_pending = 1; - is_graceful = 0; - signal(SIGTERM, SIG_DFL); -} - - - -static void sig_hup(int sig) -{ - shutdown_pending = 1; - is_graceful = 1; -} - - - -static void set_signals() -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = sig_term; - - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)"); - - sa.sa_handler = sig_hup; - - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); -} diff --git a/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm.h deleted file mode 100644 index 4b9a8392..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "scoreboard.h" - -#ifndef APACHE_MPM_THREADED_H -#define APACHE_MPM_THREADED_H - -#define THREADED_MPM - -#define MPM_NAME "NetWare_Threaded" - -/*#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES - #define AP_MPM_WANT_WAIT_OR_TIMEOUT - #define AP_MPM_WANT_PROCESS_CHILD_STATUS - #define AP_MPM_WANT_SET_PIDFILE - #define AP_MPM_WANT_SET_SCOREBOARD - #define AP_MPM_WANT_SET_LOCKFILE -*/ -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_MAX_MEM_FREE -#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK -/*#define AP_MPM_WANT_SET_COREDUMPDIR - #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -*/ - -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -extern int ap_threads_per_child; -extern int ap_thread_stack_size; -extern int ap_max_workers_limit; -extern server_rec *ap_server_conf; - -#endif /* APACHE_MPM_THREADED_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm_default.h deleted file mode 100644 index 397f5511..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm_default.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#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 1 -#endif - -/* Maximum number of *free* server processes --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_FREE_DAEMON -#define DEFAULT_MAX_FREE_DAEMON 1 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_FREE_DAEMON -#define DEFAULT_MIN_FREE_DAEMON 1 -#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. - */ -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 2048 -#endif - -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 50 -#endif - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREADS -#define DEFAULT_START_THREADS DEFAULT_THREADS_PER_CHILD -#endif - -/* Maximum number of *free* threads --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_FREE_THREADS -#define DEFAULT_MAX_FREE_THREADS 100 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_FREE_THREADS -#define DEFAULT_MIN_FREE_THREADS 10 -#endif - -/* Check for definition of DEFAULT_REL_RUNTIMEDIR */ -#ifndef DEFAULT_REL_RUNTIMEDIR -#define DEFAULT_REL_RUNTIMEDIR "logs" -#endif - -/* File used for accept locking, when we use a file */ -/*#ifndef DEFAULT_LOCKFILE - #define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" - #endif -*/ - -/* Where the main/parent process's pid is logged */ -/*#ifndef DEFAULT_PIDLOG - #define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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 0 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm_netware.c b/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm_netware.c deleted file mode 100644 index f3eb227c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/netware/mpm_netware.c +++ /dev/null @@ -1,1295 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * httpd.c: simple http daemon for answering WWW file requests - * - * - * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) - * - * 03-06-95 blong - * changed server number for child-alone processes to 0 and changed name - * of processes - * - * 03-10-95 blong - * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) - * including set group before fork, and call gettime before to fork - * to set up libraries. - * - * 04-14-95 rst / rh - * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the - * Apache server, and also to have child processes do accept() directly. - * - * April-July '95 rst - * Extensive rework for Apache. - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" -#include "apr_tables.h" -#include "apr_getopt.h" -#include "apr_thread_mutex.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "mpm_default.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "scoreboard.h" -#include "ap_mpm.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "ap_mmn.h" - -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#include <signal.h> - -#include <netware.h> -#include <nks/netware.h> -#include <library.h> -#include <screen.h> - -/* 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. - */ -#ifndef HARD_SERVER_LIMIT -#define HARD_SERVER_LIMIT 1 -#endif - -#define WORKER_DEAD SERVER_DEAD -#define WORKER_STARTING SERVER_STARTING -#define WORKER_READY SERVER_READY -#define WORKER_IDLE_KILL SERVER_IDLE_KILL - -/* config globals */ - -int ap_threads_per_child=0; /* Worker threads per child */ -int ap_thread_stack_size=65536; -static int ap_threads_to_start=0; -static int ap_threads_min_free=0; -static int ap_threads_max_free=0; -static int ap_threads_limit=0; -static int mpm_state = AP_MPMQ_STARTING; - -/* - * 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_workers_limit = -1; -server_rec *ap_server_conf; - -/* *Non*-shared http_main globals... */ - -int hold_screen_on_exit = 0; /* Indicates whether the screen should be held open */ - -static fd_set listenfds; -static int listenmaxfd; - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pmain; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ -static char *ap_my_addrspace = NULL; - -static int die_now = 0; - -/* Keep track of the number of worker threads currently active */ -static unsigned long worker_thread_count; -static int request_count; - -/* Structure used to register/deregister a console handler with the OS */ -static int InstallConsoleHandler(void); -static void RemoveConsoleHandler(void); -static int CommandLineInterpreter(scr_t screenID, const char *commandLine); -static CommandParser_t ConsoleHandler = {0, NULL, 0}; -#define HANDLEDCOMMAND 0 -#define NOTMYCOMMAND 1 - -static int show_settings = 0; - -//#define DBINFO_ON -//#define DBPRINT_ON -#ifdef DBPRINT_ON -#define DBPRINT0(s) printf(s) -#define DBPRINT1(s,v1) printf(s,v1) -#define DBPRINT2(s,v1,v2) printf(s,v1,v2) -#else -#define DBPRINT0(s) -#define DBPRINT1(s,v1) -#define DBPRINT2(s,v1,v2) -#endif - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -static int volatile wait_to_finish=1; -ap_generation_t volatile ap_my_generation=0; - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans, - apr_bucket_alloc_t *bucket_alloc) __attribute__ ((noreturn)); -static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans, - apr_bucket_alloc_t *bucket_alloc) -{ - apr_bucket_alloc_destroy(bucket_alloc); - if (!shutdown_pending) { - apr_pool_destroy(ptrans); - } - - atomic_dec (&worker_thread_count); - if (worker_num >=0) - ap_update_child_status_from_indexes(0, worker_num, WORKER_DEAD, - (request_rec *) NULL); - NXThreadExit((void*)&code); -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = 1; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_limit; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = ap_threads_min_free; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = ap_threads_max_free; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = 1; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - - -/***************************************************************** - * Connection structures and accounting... - */ - -static void mpm_term(void) -{ - RemoveConsoleHandler(); - wait_to_finish = 0; - NXThreadYield(); -} - -static void sig_term(int sig) -{ - 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; - - DBPRINT0 ("waiting for threads\n"); - while (wait_to_finish) { - apr_thread_yield(); - } - DBPRINT0 ("goodbye\n"); -} - -/* restart() is the signal handler for SIGHUP and SIGWINCH - * in the parent process, unless running in ONE_PROCESS mode - */ -static void restart(void) -{ - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = 1; -} - -static void set_signals(void) -{ - apr_signal(SIGTERM, sig_term); - apr_signal(SIGABRT, sig_term); -} - -int nlmUnloadSignaled(int wait) -{ - shutdown_pending = 1; - - if (wait) { - while (wait_to_finish) { - NXThreadYield(); - } - } - - return 0; -} - -/***************************************************************** - * Child process main loop. - * The following vars are static to avoid getting clobbered by longjmp(); - * they are really private to child_main. - */ - - -int ap_graceful_stop_signalled(void) -{ - /* not ever called anymore... */ - return 0; -} - -#define MAX_WB_RETRIES 3 -#ifdef DBINFO_ON -static int would_block = 0; -static int retry_success = 0; -static int retry_fail = 0; -static int avg_retries = 0; -#endif - -/*static */ -void worker_main(void *arg) -{ - ap_listen_rec *lr, *first_lr, *last_lr = NULL; - apr_pool_t *ptrans; - apr_pool_t *pbucket; - apr_allocator_t *allocator; - apr_bucket_alloc_t *bucket_alloc; - conn_rec *current_conn; - apr_status_t stat = APR_EINIT; - ap_sb_handle_t *sbh; - - int my_worker_num = (int)arg; - apr_socket_t *csd = NULL; - int requests_this_child = 0; - apr_socket_t *sd = NULL; - fd_set main_fds; - - int sockdes; - int srv; - struct timeval tv; - int wouldblock_retry; - - tv.tv_sec = 1; - tv.tv_usec = 0; - - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - - apr_pool_create_ex(&ptrans, pmain, NULL, allocator); - apr_allocator_owner_set(allocator, ptrans); - apr_pool_tag(ptrans, "transaction"); - - bucket_alloc = apr_bucket_alloc_create_ex(allocator); - - atomic_inc (&worker_thread_count); - - while (!die_now) { - /* - * (Re)initialize this child to a pre-connection state. - */ - current_conn = NULL; - apr_pool_clear(ptrans); - - if ((ap_max_requests_per_child > 0 - && requests_this_child++ >= ap_max_requests_per_child)) { - DBPRINT1 ("\n**Thread slot %d is shutting down", my_worker_num); - clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); - } - - ap_update_child_status_from_indexes(0, my_worker_num, WORKER_READY, - (request_rec *) NULL); - - /* - * Wait for an acceptable connection to arrive. - */ - - for (;;) { - if (shutdown_pending || restart_pending || (ap_scoreboard_image->servers[0][my_worker_num].status == WORKER_IDLE_KILL)) { - DBPRINT1 ("\nThread slot %d is shutting down\n", my_worker_num); - clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); - } - - /* Check the listen queue on all sockets for requests */ - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - srv = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); - - if (srv <= 0) { - if (srv < 0) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, WSAGetLastError(), ap_server_conf, - "select() failed on listen socket"); - apr_thread_yield(); - } - continue; - } - - /* remember the last_lr we searched last time around so that - we don't end up starving any particular listening socket */ - if (last_lr == NULL) { - lr = ap_listeners; - } - else { - lr = last_lr->next; - if (!lr) - lr = ap_listeners; - } - first_lr = lr; - do { - apr_os_sock_get(&sockdes, lr->sd); - if (FD_ISSET(sockdes, &main_fds)) - goto got_listener; - lr = lr->next; - if (!lr) - lr = ap_listeners; - } while (lr != first_lr); - /* if we get here, something unexpected happened. Go back - into the select state and try again. - */ - continue; - got_listener: - last_lr = lr; - sd = lr->sd; - - wouldblock_retry = MAX_WB_RETRIES; - - while (wouldblock_retry) { - if ((stat = apr_accept(&csd, sd, ptrans)) == APR_SUCCESS) { - break; - } - else { - /* if the error is a wouldblock then maybe we were too - quick try to pull the next request from the listen - queue. Try a few more times then return to our idle - listen state. */ - if (!APR_STATUS_IS_EAGAIN(stat)) { - break; - } - - if (wouldblock_retry--) { - apr_thread_yield(); - } - } - } - - /* If we got a new socket, set it to non-blocking mode and process - it. Otherwise handle the error. */ - if (stat == APR_SUCCESS) { - apr_socket_opt_set(csd, APR_SO_NONBLOCK, 0); -#ifdef DBINFO_ON - if (wouldblock_retry < MAX_WB_RETRIES) { - retry_success++; - avg_retries += (MAX_WB_RETRIES-wouldblock_retry); - } -#endif - break; /* We have a socket ready for reading */ - } - else { -#ifdef DBINFO_ON - if (APR_STATUS_IS_EAGAIN(stat)) { - would_block++; - retry_fail++; - } - else -#else - if (APR_STATUS_IS_EAGAIN(stat) || -#endif - APR_STATUS_IS_ECONNRESET(stat) || - APR_STATUS_IS_ETIMEDOUT(stat) || - APR_STATUS_IS_EHOSTUNREACH(stat) || - APR_STATUS_IS_ENETUNREACH(stat)) { - ; - } - else if (APR_STATUS_IS_ENETDOWN(stat)) { - /* - * When the network layer has been shut down, there - * is not much use in simply exiting: the parent - * would simply re-create us (and we'd fail again). - * Use the CHILDFATAL code to tear the server down. - * @@@ Martin's idea for possible improvement: - * A different approach would be to define - * a new APEXIT_NETDOWN exit code, the reception - * of which would make the parent shutdown all - * children, then idle-loop until it detected that - * the network is up again, and restart the children. - * Ben Hyde noted that temporary ENETDOWN situations - * occur in mobile IP. - */ - ap_log_error(APLOG_MARK, APLOG_EMERG, stat, ap_server_conf, - "apr_accept: giving up."); - clean_child_exit(APEXIT_CHILDFATAL, my_worker_num, ptrans, - bucket_alloc); - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, stat, ap_server_conf, - "apr_accept: (client socket)"); - clean_child_exit(1, my_worker_num, ptrans, bucket_alloc); - } - } - } - - ap_create_sb_handle(&sbh, ptrans, 0, my_worker_num); - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, - my_worker_num, sbh, - bucket_alloc); - if (current_conn) { - ap_process_connection(current_conn, csd); - ap_lingering_close(current_conn); - } - request_count++; - } - clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); -} - - -static int make_child(server_rec *s, int slot) -{ - int tid; - int err=0; - NXContext_t ctx; - - if (slot + 1 > ap_max_workers_limit) { - ap_max_workers_limit = slot + 1; - } - - ap_update_child_status_from_indexes(0, slot, WORKER_STARTING, - (request_rec *) NULL); - - if (ctx = NXContextAlloc((void (*)(void *)) worker_main, (void*)slot, NX_PRIO_MED, ap_thread_stack_size, NX_CTX_NORMAL, &err)) { - char threadName[32]; - - sprintf (threadName, "Apache_Worker %d", slot); - NXContextSetName(ctx, threadName); - err = NXThreadCreate(ctx, NX_THR_BIND_CONTEXT, &tid); - if (err) { - NXContextFree (ctx); - } - } - - if (err) { - /* create thread didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - ap_update_child_status_from_indexes(0, slot, WORKER_DEAD, - (request_rec *) NULL); - - /* 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. */ - apr_thread_yield(); - - return -1; - } - - ap_scoreboard_image->servers[0][slot].tid = tid; - - return 0; -} - - -/* start up a bunch of worker threads */ -static void startup_workers(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_threads_limit; ++i) { - if (ap_scoreboard_image->servers[0][i].status != WORKER_DEAD) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * idle_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 idle_spawn_rate = 1; -#ifndef MAX_SPAWN_RATE -#define MAX_SPAWN_RATE (64) -#endif -static int hold_off_on_exponential_spawning; - -static void perform_idle_server_maintenance(apr_pool_t *p) -{ - int i; - int to_kill; - int idle_count; - worker_score *ws; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - - /* initialize the free_list */ - free_length = 0; - - to_kill = -1; - idle_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - for (i = 0; i < ap_threads_limit; ++i) { - int status; - - if (i >= ap_max_workers_limit && free_length == idle_spawn_rate) - break; - ws = &ap_scoreboard_image->servers[0][i]; - status = ws->status; - if (status == WORKER_DEAD) { - /* try to keep children numbers as low as possible */ - if (free_length < idle_spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else if (status == WORKER_IDLE_KILL) { - /* If it is already marked to die, skip it */ - continue; - } - else { - /* We consider a starting server as idle because we started it - * at least a cycle ago, and if it still hasn't finished starting - * then we're just going to swamp things worse by forking more. - * So we hopefully won't need to fork more if we count it. - * This depends on the ordering of SERVER_READY and SERVER_STARTING. - */ - if (status <= WORKER_READY) { - ++ idle_count; - /* always kill the highest numbered child if we have to... - * no really well thought out reason ... other than observing - * the server behaviour under linux where lower numbered children - * tend to service more hits (and hence are more likely to have - * their data in cpu caches). - */ - to_kill = i; - } - - ++total_non_dead; - last_non_dead = i; - } - } - DBPRINT2("Total: %d Idle Count: %d \r", total_non_dead, idle_count); - ap_max_workers_limit = last_non_dead + 1; - if (idle_count > ap_threads_max_free) { - /* kill off one child... we use the pod because that'll cause it to - * shut down gracefully, in case it happened to pick up a request - * while we were counting - */ - idle_spawn_rate = 1; - ap_update_child_status_from_indexes(0, last_non_dead, WORKER_IDLE_KILL, - (request_rec *) NULL); - DBPRINT1("\nKilling idle thread: %d\n", last_non_dead); - } - else if (idle_count < ap_threads_min_free) { - /* terminate the free list */ - if (free_length == 0) { - /* only report this condition once */ - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "server reached MaxClients setting, consider" - " raising the MaxClients setting"); - reported = 1; - } - idle_spawn_rate = 1; - } - else { - if (idle_spawn_rate >= 8) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "server seems busy, (you may need " - "to increase StartServers, or Min/MaxSpareServers), " - "spawning %d children, there are %d idle, and " - "%d total children", idle_spawn_rate, - idle_count, total_non_dead); - } - DBPRINT0("\n"); - for (i = 0; i < free_length; ++i) { - DBPRINT1("Spawning additional thread slot: %d\n", free_slots[i]); - make_child(ap_server_conf, free_slots[i]); - } - /* 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 (idle_spawn_rate < MAX_SPAWN_RATE) { - idle_spawn_rate *= 2; - } - } - } - else { - idle_spawn_rate = 1; - } -} - -static void display_settings () -{ - int status_array[SERVER_NUM_STATUS]; - int i, status, total=0; - int reqs = request_count; -#ifdef DBINFO_ON - int wblock = would_block; - - would_block = 0; -#endif - - request_count = 0; - - ClearScreen (getscreenhandle()); - printf("%s \n", ap_get_server_version()); - - for (i=0;i<SERVER_NUM_STATUS;i++) { - status_array[i] = 0; - } - - for (i = 0; i < ap_threads_limit; ++i) { - status = (ap_scoreboard_image->servers[0][i]).status; - status_array[status]++; - } - - for (i=0;i<SERVER_NUM_STATUS;i++) { - switch(i) - { - case SERVER_DEAD: - printf ("Available:\t%d\n", status_array[i]); - break; - case SERVER_STARTING: - printf ("Starting:\t%d\n", status_array[i]); - break; - case SERVER_READY: - printf ("Ready:\t\t%d\n", status_array[i]); - break; - case SERVER_BUSY_READ: - printf ("Busy:\t\t%d\n", status_array[i]); - break; - case SERVER_BUSY_WRITE: - printf ("Busy Write:\t%d\n", status_array[i]); - break; - case SERVER_BUSY_KEEPALIVE: - printf ("Busy Keepalive:\t%d\n", status_array[i]); - break; - case SERVER_BUSY_LOG: - printf ("Busy Log:\t%d\n", status_array[i]); - break; - case SERVER_BUSY_DNS: - printf ("Busy DNS:\t%d\n", status_array[i]); - break; - case SERVER_CLOSING: - printf ("Closing:\t%d\n", status_array[i]); - break; - case SERVER_GRACEFUL: - printf ("Restart:\t%d\n", status_array[i]); - break; - case SERVER_IDLE_KILL: - printf ("Idle Kill:\t%d\n", status_array[i]); - break; - default: - printf ("Unknown Status:\t%d\n", status_array[i]); - break; - } - if (i != SERVER_DEAD) - total+=status_array[i]; - } - printf ("Total Running:\t%d\tout of: \t%d\n", total, ap_threads_limit); - printf ("Requests per interval:\t%d\n", reqs); - -#ifdef DBINFO_ON - printf ("Would blocks:\t%d\n", wblock); - printf ("Successful retries:\t%d\n", retry_success); - printf ("Failed retries:\t%d\n", retry_fail); - printf ("Avg retries:\t%d\n", retry_success == 0 ? 0 : avg_retries / retry_success); -#endif -} - -static void show_server_data() -{ - ap_listen_rec *lr; - module **m; - - printf("%s\n", ap_get_server_version()); - if (ap_my_addrspace && (ap_my_addrspace[0] != 'O') && (ap_my_addrspace[1] != 'S')) - printf(" Running in address space %s\n", ap_my_addrspace); - - - /* Display listening ports */ - printf(" Listening on port(s):"); - lr = ap_listeners; - do { - printf(" %d", lr->bind_addr->port); - lr = lr->next; - } while(lr && lr != ap_listeners); - - /* Display dynamic modules loaded */ - printf("\n"); - for (m = ap_loaded_modules; *m != NULL; m++) { - if (((module*)*m)->dynamic_load_handle) { - printf(" Loaded dynamic module %s\n", ((module*)*m)->name); - } - } -} - - -static int setup_listeners(server_rec *s) -{ - ap_listen_rec *lr; - int sockdes; - - if (ap_setup_listeners(s) < 1 ) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return -1; - } - - listenmaxfd = -1; - FD_ZERO(&listenfds); - for (lr = ap_listeners; lr; lr = lr->next) { - apr_os_sock_get(&sockdes, lr->sd); - FD_SET(sockdes, &listenfds); - if (sockdes > listenmaxfd) { - listenmaxfd = sockdes; - } - } - return 0; -} - -static int shutdown_listeners() -{ - ap_listen_rec *lr; - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_socket_close(lr->sd); - } - ap_listeners = NULL; - return 0; -} - -/***************************************************************** - * Executive routines. - */ - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - apr_status_t status=0; - - pconf = _pconf; - ap_server_conf = s; - - if (setup_listeners(s)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, status, s, - "no listening sockets available, shutting down"); - return -1; - } - - restart_pending = shutdown_pending = 0; - worker_thread_count = 0; - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_NOT_SHARED) != OK) { - return 1; - } - } - - /* Only set slot 0 since that is all NetWare will ever have. */ - ap_scoreboard_image->parent[0].pid = getpid(); - - set_signals(); - - apr_pool_create(&pmain, pconf); - ap_run_child_init(pmain, ap_server_conf); - - if (ap_threads_max_free < ap_threads_min_free + 1) /* Don't thrash... */ - ap_threads_max_free = ap_threads_min_free + 1; - request_count = 0; - - startup_workers(ap_threads_to_start); - - /* Allow the Apache screen to be closed normally on exit() only if it - has not been explicitly forced to close on exit(). (ie. the -E flag - was specified at startup) */ - if (hold_screen_on_exit > 0) { - hold_screen_on_exit = 0; - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(accept_mutex), - apr_proc_mutex_defname()); -#endif - show_server_data(); - - mpm_state = AP_MPMQ_RUNNING; - while (!restart_pending && !shutdown_pending) { - perform_idle_server_maintenance(pconf); - if (show_settings) - display_settings(); - apr_thread_yield(); - apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL); - } - mpm_state = AP_MPMQ_STOPPING; - - - /* Shutdown the listen sockets so that we don't get stuck in a blocking call. - shutdown_listeners();*/ - - if (shutdown_pending) { /* Got an unload from the console */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - - while (worker_thread_count > 0) { - printf ("\rShutdown pending. Waiting for %d thread(s) to terminate...", - worker_thread_count); - apr_thread_yield(); - } - - return 1; - } - else { /* the only other way out is a restart */ - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "Graceful restart requested, doing restart"); - - /* Wait for all of the threads to terminate before initiating the restart */ - while (worker_thread_count > 0) { - printf ("\rRestart pending. Waiting for %d thread(s) to terminate...", - worker_thread_count); - apr_thread_yield(); - } - printf ("\nRestarting...\n"); - } - - return 0; -} - -static int netware_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - int debug; - char *addrname = NULL; - - mpm_state = AP_MPMQ_STARTING; - - debug = ap_exists_config_define("DEBUG"); - - is_graceful = 0; - ap_my_pid = getpid(); - addrname = getaddressspacename (NULL, NULL); - if (addrname) { - ap_my_addrspace = apr_pstrdup (p, addrname); - free (addrname); - } - - ap_listen_pre_config(); - ap_threads_to_start = DEFAULT_START_THREADS; - ap_threads_min_free = DEFAULT_MIN_FREE_THREADS; - ap_threads_max_free = DEFAULT_MAX_FREE_THREADS; - ap_threads_limit = HARD_THREAD_LIMIT; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - return OK; -} - -static void netware_mpm_hooks(apr_pool_t *p) -{ - ap_hook_pre_config(netware_pre_config, NULL, NULL, APR_HOOK_MIDDLE); -} - -void netware_rewrite_args(process_rec *process) -{ - char *def_server_root; - char optbuf[3]; - const char *opt_arg; - apr_getopt_t *opt; - apr_array_header_t *mpm_new_argv; - - - atexit (mpm_term); - InstallConsoleHandler(); - - /* Make sure to hold the Apache screen open if exit() is called */ - hold_screen_on_exit = 1; - - /* Rewrite process->argv[]; - * - * add default -d serverroot from the path of this executable - * - * The end result will look like: - * The -d serverroot default from the running executable - */ - if (process->argc > 0) { - char *s = apr_pstrdup (process->pconf, process->argv[0]); - if (s) { - int i, len = strlen(s); - - for (i=len; i; i--) { - if (s[i] == '\\' || s[i] == '/') { - s[i] = '\0'; - apr_filepath_merge(&def_server_root, NULL, s, - APR_FILEPATH_TRUENAME, process->pool); - break; - } - } - /* Use process->pool so that the rewritten argv - * lasts for the lifetime of the server process, - * because pconf will be destroyed after the - * initial pre-flight of the config parser. - */ - mpm_new_argv = apr_array_make(process->pool, process->argc + 2, - sizeof(const char *)); - *(const char **)apr_array_push(mpm_new_argv) = process->argv[0]; - *(const char **)apr_array_push(mpm_new_argv) = "-d"; - *(const char **)apr_array_push(mpm_new_argv) = def_server_root; - - optbuf[0] = '-'; - optbuf[2] = '\0'; - apr_getopt_init(&opt, process->pool, process->argc, (char**) process->argv); - while (apr_getopt(opt, AP_SERVER_BASEARGS"n:", optbuf + 1, &opt_arg) == APR_SUCCESS) { - switch (optbuf[1]) { - case 'n': - if (opt_arg) { - renamescreen(opt_arg); - } - break; - case 'E': - /* Don't need to hold the screen open if the output is going to a file */ - hold_screen_on_exit = -1; - default: - *(const char **)apr_array_push(mpm_new_argv) = - apr_pstrdup(process->pool, optbuf); - - if (opt_arg) { - *(const char **)apr_array_push(mpm_new_argv) = opt_arg; - } - break; - } - } - process->argc = mpm_new_argv->nelts; - process->argv = (const char * const *) mpm_new_argv->elts; - } - } -} - -static int CommandLineInterpreter(scr_t screenID, const char *commandLine) -{ - char *szCommand = "APACHE2 "; - int iCommandLen = 8; - char szcommandLine[256]; - char *pID; - screenID = screenID; - - - if (commandLine == NULL) - return NOTMYCOMMAND; - if (strlen(commandLine) <= strlen(szCommand)) - return NOTMYCOMMAND; - - strncpy (szcommandLine, commandLine, sizeof(szcommandLine)-1); - - /* All added commands begin with "APACHE2 " */ - - if (!strnicmp(szCommand, szcommandLine, iCommandLen)) { - ActivateScreen (getscreenhandle()); - - /* If an instance id was not given but the nlm is loaded in - protected space, then the the command belongs to the - OS address space instance to pass it on. */ - pID = strstr (szcommandLine, "-p"); - if ((pID == NULL) && nlmisloadedprotected()) - return NOTMYCOMMAND; - - /* If we got an instance id but it doesn't match this - instance of the nlm, pass it on. */ - if (pID) { - pID = &pID[2]; - while (*pID && (*pID == ' ')) - pID++; - } - if (pID && ap_my_addrspace && strnicmp(pID, ap_my_addrspace, strlen(ap_my_addrspace))) - return NOTMYCOMMAND; - - /* If we have determined that this command belongs to this - instance of the nlm, then handle it. */ - if (!strnicmp("RESTART",&szcommandLine[iCommandLen],3)) { - printf("Restart Requested...\n"); - restart(); - } - else if (!strnicmp("VERSION",&szcommandLine[iCommandLen],3)) { - printf("Server version: %s\n", ap_get_server_version()); - printf("Server built: %s\n", ap_get_server_built()); - } - else if (!strnicmp("MODULES",&szcommandLine[iCommandLen],3)) { - ap_show_modules(); - } - else if (!strnicmp("DIRECTIVES",&szcommandLine[iCommandLen],3)) { - ap_show_directives(); - } - else if (!strnicmp("SHUTDOWN",&szcommandLine[iCommandLen],3)) { - printf("Shutdown Requested...\n"); - shutdown_pending = 1; - } - else if (!strnicmp("SETTINGS",&szcommandLine[iCommandLen],3)) { - if (show_settings) { - show_settings = 0; - ClearScreen (getscreenhandle()); - show_server_data(); - } - else { - show_settings = 1; - display_settings(); - } - } - else { - show_settings = 0; - if (strnicmp("HELP",&szcommandLine[iCommandLen],3)) - printf("Unknown APACHE2 command %s\n", &szcommandLine[iCommandLen]); - printf("Usage: APACHE2 [command] [-p <instance ID>]\n"); - printf("Commands:\n"); - printf("\tDIRECTIVES - Show directives\n"); - printf("\tHELP - Display this help information\n"); - printf("\tMODULES - Show a list of the loaded modules\n"); - printf("\tRESTART - Reread the configuration file and restart Apache\n"); - printf("\tSETTINGS - Show current thread status\n"); - printf("\tSHUTDOWN - Shutdown Apache\n"); - printf("\tVERSION - Display the server version information\n"); - } - - /* Tell NetWare we handled the command */ - return HANDLEDCOMMAND; - } - - /* Tell NetWare that the command isn't mine */ - return NOTMYCOMMAND; -} - -static int InstallConsoleHandler(void) -{ - /* Our command line handler interfaces the system operator - with this NLM */ - - NX_WRAP_INTERFACE(CommandLineInterpreter, 2, (void*)&(ConsoleHandler.parser)); - - ConsoleHandler.rTag = AllocateResourceTag(getnlmhandle(), "Command Line Processor", - ConsoleCommandSignature); - if (!ConsoleHandler.rTag) - { - printf("Error on allocate resource tag\n"); - return 1; - } - - RegisterConsoleCommand(&ConsoleHandler); - - /* The Remove procedure unregisters the console handler */ - - return 0; -} - -static void RemoveConsoleHandler(void) -{ - UnRegisterConsoleCommand(&ConsoleHandler); - NX_UNWRAP_INTERFACE(ConsoleHandler.parser); -} - -static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, const 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_free_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_min_free = atoi(arg); - if (ap_threads_min_free <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareServers set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - ap_threads_min_free = 1; - } - - return NULL; -} - -static const char *set_max_free_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_max_free = atoi(arg); - return NULL; -} - -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_limit = atoi(arg); - if (ap_threads_limit > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxThreads of %d exceeds compile time limit " - "of %d threads,", ap_threads_limit, HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering MaxThreads to %d. To increase, please " - "see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " HARD_THREAD_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - ap_threads_limit = HARD_THREAD_LIMIT; - } - else if (ap_threads_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxThreads > 0, setting to 1"); - ap_threads_limit = 1; - } - return NULL; -} - -static const char *set_thread_stacksize(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_thread_stack_size = atoi(arg); - return NULL; -} - -static const command_rec netware_mpm_cmds[] = { -AP_INIT_TAKE1("ThreadStackSize", set_thread_stacksize, NULL, RSRC_CONF, - "Stack size each created thread will use."), -LISTEN_COMMANDS, -AP_INIT_TAKE1("StartThreads", set_threads_to_start, NULL, RSRC_CONF, - "Number of worker threads launched at server startup"), -AP_INIT_TAKE1("MinSpareThreads", set_min_free_threads, NULL, RSRC_CONF, - "Minimum number of idle threads, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_free_threads, NULL, RSRC_CONF, - "Maximum number of idle threads"), -AP_INIT_TAKE1("MaxThreads", set_thread_limit, NULL, RSRC_CONF, - "Maximum number of worker threads alive at the same time"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_netware_module = { - MPM20_MODULE_STUFF, - netware_rewrite_args, /* 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 */ - netware_mpm_cmds, /* command apr_table_t */ - netware_mpm_hooks, /* register hooks */ -}; diff --git a/rubbos/app/httpd-2.0.64/server/mpm/prefork/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/prefork/Makefile.in deleted file mode 100644 index 034bf5ce..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/prefork/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libprefork.la -LTLIBRARY_SOURCES = prefork.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/prefork/config.m4 b/rubbos/app/httpd-2.0.64/server/mpm/prefork/config.m4 deleted file mode 100644 index 9c189a86..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/prefork/config.m4 +++ /dev/null @@ -1,3 +0,0 @@ -if test "$MPM_NAME" = "prefork" ; then - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/prefork/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/prefork/mpm.h deleted file mode 100644 index 51f810b3..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/prefork/mpm.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "httpd.h" -#include "mpm_default.h" -#include "scoreboard.h" -#include "unixd.h" - -#ifndef APACHE_MPM_PREFORK_H -#define APACHE_MPM_PREFORK_H - -#define PREFORK_MPM - -#define MPM_NAME "Prefork" - -#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT -#define AP_MPM_WANT_PROCESS_CHILD_STATUS -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_LOCKFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -#define AP_MPM_WANT_SIGNAL_SERVER -#define AP_MPM_WANT_SET_MAX_MEM_FREE -#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER -#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK - -#define AP_MPM_USES_POD 1 -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -#define MPM_ACCEPT_FUNC unixd_accept - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; -#endif /* APACHE_MPM_PREFORK_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/prefork/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/prefork/mpm_default.h deleted file mode 100644 index 8ddf38f0..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/prefork/mpm_default.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#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 - -/* 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 - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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/rubbos/app/httpd-2.0.64/server/mpm/prefork/prefork.c b/rubbos/app/httpd-2.0.64/server/mpm/prefork/prefork.c deleted file mode 100644 index 8667b4ab..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/prefork/prefork.c +++ /dev/null @@ -1,1355 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "mpm_default.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "scoreboard.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "ap_mmn.h" -#include "apr_poll.h" - -#ifdef HAVE_BSTRING_H -#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_SYS_PROCESSOR_H -#include <sys/processor.h> /* for bindprocessor() */ -#endif - -#include <signal.h> -#include <sys/times.h> - -/* 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. - */ -#ifndef DEFAULT_SERVER_LIMIT -#define DEFAULT_SERVER_LIMIT 256 -#endif - -/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_SERVER_LIMIT -#define MAX_SERVER_LIMIT 20000 -#endif - -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 1 -#endif - -/* config globals */ - -int ap_threads_per_child=0; /* Worker threads per child */ -static apr_proc_mutex_t *accept_mutex; -static int ap_daemons_to_start=0; -static int ap_daemons_min_free=0; -static int ap_daemons_max_free=0; -static int ap_daemons_limit=0; /* MaxClients */ -static int server_limit = DEFAULT_SERVER_LIMIT; -static int first_server_limit; -static int changed_limit_at_restart; -static int mpm_state = AP_MPMQ_STARTING; -static ap_pod_t *pod; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We - * use this value to optimize routines that have to scan the entire scoreboard. - */ -int ap_max_daemons_limit = -1; -server_rec *ap_server_conf; - -/* one_process --- debugging mode variable; can be set from the command line - * with the -X flag. If set, this gets you the child_main loop running - * in the process which originally started up (no detach, no make_child), - * which is a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -static int one_process = 0; - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ -static pid_t parent_pid; -#ifndef MULTITHREAD -static int my_child_num; -#endif -ap_generation_t volatile ap_my_generation=0; - -#ifdef TPF -int tpf_child = 0; -char tpf_server_name[INETD_SERVNAME_LENGTH+1]; -#endif /* TPF */ - -static int die_now = 0; - -#ifdef GPROF -/* - * change directory for gprof to plop the gmon.out file - * configure in httpd.conf: - * GprofDir $RuntimeDir/ -> $ServerRoot/$RuntimeDir/gmon.out - * GprofDir $RuntimeDir/% -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out - */ -static void chdir_for_gprof(void) -{ - core_server_config *sconf = - ap_get_module_config(ap_server_conf->module_config, &core_module); - char *dir = sconf->gprof_dir; - const char *use_dir; - - if(dir) { - apr_status_t res; - char buf[512]; - int len = strlen(sconf->gprof_dir) - 1; - if(*(dir + len) == '%') { - dir[len] = '\0'; - apr_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid()); - } - use_dir = ap_server_root_relative(pconf, buf[0] ? buf : dir); - res = apr_dir_make(use_dir, 0755, pconf); - if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, - "gprof: error creating directory %s", dir); - } - } - else { - use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR); - } - - chdir(use_dir); -} -#else -#define chdir_for_gprof() -#endif - -/* XXX - I don't know if TPF will ever use this module or not, so leave - * the ap_check_signals calls in but disable them - manoj */ -#define ap_check_signals() - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) __attribute__ ((noreturn)); -static void clean_child_exit(int code) -{ - mpm_state = AP_MPMQ_STOPPING; - - if (pchild) { - apr_pool_destroy(pchild); - } - ap_mpm_pod_close(pod); - chdir_for_gprof(); - exit(code); -} - -static void accept_mutex_on(void) -{ - apr_status_t rv = apr_proc_mutex_lock(accept_mutex); - if (rv != APR_SUCCESS) { - const char *msg = "couldn't grab the accept mutex"; - - if (ap_my_generation != - ap_scoreboard_image->global->running_generation) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg); - clean_child_exit(0); - } - else { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg); - exit(APEXIT_CHILDFATAL); - } - } -} - -static void accept_mutex_off(void) -{ - apr_status_t rv = apr_proc_mutex_unlock(accept_mutex); - if (rv != APR_SUCCESS) { - const char *msg = "couldn't release the accept mutex"; - - if (ap_my_generation != - ap_scoreboard_image->global->running_generation) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg); - /* don't exit here... we have a connection to - * process, after which point we'll see that the - * generation changed and we'll exit cleanly - */ - } - else { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg); - exit(APEXIT_CHILDFATAL); - } - } -} - -/* On some architectures it's safe to do unserialized accept()s in the single - * Listen case. But it's never safe to do it in the case where there's - * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT - * when it's safe in the single Listen case. - */ -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0) -#else -#define SAFE_ACCEPT(stmt) do {stmt;} while(0) -#endif - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = server_limit; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = ap_daemons_min_free; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = ap_daemons_max_free; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = server_limit; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -#if defined(NEED_WAITPID) -/* - Systems without a real waitpid sometimes lose a child's exit while waiting - for another. Search through the scoreboard for missing children. - */ -int reap_children(int *exitcode, apr_exit_why_e *status) -{ - int n, pid; - - for (n = 0; n < ap_max_daemons_limit; ++n) { - if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && - kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { - ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL); - /* just mark it as having a successful exit status */ - *status = APR_PROC_EXIT; - *exitcode = 0; - return(pid); - } - } - return 0; -} -#endif - -/***************************************************************** - * Connection structures and accounting... - */ - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; - -static void sig_term(int sig) -{ - 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; -} - -/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL - * in the parent process, unless running in ONE_PROCESS mode - */ -static void restart(int sig) -{ - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = (sig == AP_SIG_GRACEFUL); -} - -static void set_signals(void) -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; -#endif - - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } - -#ifndef NO_USE_SIGACTION - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)"); -#endif -#ifdef SIGXCPU - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXCPU, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)"); -#endif -#ifdef SIGXFSZ - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXFSZ, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)"); -#endif -#ifdef SIGPIPE - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy - * processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")"); -#else - if (!one_process) { -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef AP_SIG_GRACEFUL - apr_signal(AP_SIG_GRACEFUL, restart); -#endif /* AP_SIG_GRACEFUL */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Child process main loop. - * The following vars are static to avoid getting clobbered by longjmp(); - * they are really private to child_main. - */ - -static int requests_this_child; -static int num_listensocks = 0; -static ap_listen_rec *listensocks; - -int ap_graceful_stop_signalled(void) -{ - /* not ever called anymore... */ - return 0; -} - - -static void child_main(int child_num_arg) -{ - apr_pool_t *ptrans; - apr_allocator_t *allocator; - conn_rec *current_conn; - apr_status_t status = APR_EINIT; - int i; - ap_listen_rec *lr; - int curr_pollfd, last_pollfd = 0; - apr_pollfd_t *pollset; - int offset; - void *csd; - ap_sb_handle_t *sbh; - apr_status_t rv; - apr_bucket_alloc_t *bucket_alloc; - - mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this - * child initializes - */ - - my_child_num = child_num_arg; - ap_my_pid = getpid(); - csd = NULL; - requests_this_child = 0; - - ap_fatal_signal_child_setup(ap_server_conf); - - /* Get a sub context for global allocations in this child, so that - * we can have cleanups occur when the child exits. - */ - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - apr_pool_create_ex(&pchild, pconf, NULL, allocator); - apr_allocator_owner_set(allocator, pchild); - - apr_pool_create(&ptrans, pchild); - apr_pool_tag(ptrans, "transaction"); - - /* needs to be done before we switch UIDs so we have permissions */ - ap_reopen_scoreboard(pchild, NULL, 0); - rv = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (unixd_setup_child()) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - ap_create_sb_handle(&sbh, pchild, my_child_num, 0); - - (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); - - /* Set up the pollfd array */ - listensocks = apr_pcalloc(pchild, - sizeof(*listensocks) * (num_listensocks)); - for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, i++) { - listensocks[i].accept_func = lr->accept_func; - listensocks[i].sd = lr->sd; - } - - pollset = apr_palloc(pchild, sizeof(*pollset) * num_listensocks); - pollset[0].p = pchild; - for (i = 0; i < num_listensocks; i++) { - pollset[i].desc.s = listensocks[i].sd; - pollset[i].desc_type = APR_POLL_SOCKET; - pollset[i].reqevents = APR_POLLIN; - } - - mpm_state = AP_MPMQ_RUNNING; - - bucket_alloc = apr_bucket_alloc_create(pchild); - - while (!die_now) { - /* - * (Re)initialize this child to a pre-connection state. - */ - - current_conn = NULL; - - apr_pool_clear(ptrans); - - if ((ap_max_requests_per_child > 0 - && requests_this_child++ >= ap_max_requests_per_child)) { - clean_child_exit(0); - } - - (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); - - /* - * Wait for an acceptable connection to arrive. - */ - - /* Lock around "accept", if necessary */ - SAFE_ACCEPT(accept_mutex_on()); - - if (num_listensocks == 1) { - offset = 0; - } - else { - /* multiple listening sockets - need to poll */ - for (;;) { - apr_status_t ret; - apr_int32_t n; - - ret = apr_poll(pollset, num_listensocks, &n, -1); - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - /* Single Unix documents select as returning errnos - * EBADF, EINTR, and EINVAL... and in none of those - * cases does it make sense to continue. In fact - * on Linux 2.0.x we seem to end up with EFAULT - * occasionally, and we'd loop forever due to it. - */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, ap_server_conf, - "apr_poll: (listen)"); - clean_child_exit(1); - } - /* find a listener */ - curr_pollfd = last_pollfd; - do { - curr_pollfd++; - if (curr_pollfd >= num_listensocks) { - curr_pollfd = 0; - } - /* XXX: Should we check for POLLERR? */ - if (pollset[curr_pollfd].rtnevents & APR_POLLIN) { - last_pollfd = curr_pollfd; - offset = curr_pollfd; - goto got_fd; - } - } while (curr_pollfd != last_pollfd); - - continue; - } - } - got_fd: - /* if we accept() something we don't want to die, so we have to - * defer the exit - */ - status = listensocks[offset].accept_func(&csd, - &listensocks[offset], ptrans); - SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ - - if (status == APR_EGENERAL) { - /* resource shortage or should-not-occur occured */ - clean_child_exit(1); - } - else if (status != APR_SUCCESS) { - continue; - } - - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - - current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); - if (current_conn) { - ap_process_connection(current_conn, csd); - ap_lingering_close(current_conn); - } - - /* Check the pod and the generation number after processing a - * connection so that we'll go away if a graceful restart occurred - * while we were processing the connection or we are the lucky - * idle server process that gets to die. - */ - if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ - die_now = 1; - } - else if (ap_my_generation != - ap_scoreboard_image->global->running_generation) { /* restart? */ - /* yeah, this could be non-graceful restart, in which case the - * parent will kill us soon enough, but why bother checking? - */ - die_now = 1; - } - } - clean_child_exit(0); -} - - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - apr_signal(SIGHUP, just_die); - /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */ - apr_signal(SIGINT, just_die); -#ifdef SIGQUIT - apr_signal(SIGQUIT, SIG_DFL); -#endif - apr_signal(SIGTERM, just_die); - child_main(slot); - } - - (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, - (request_rec *) NULL); - - -#ifdef _OSD_POSIX - /* BS2000 requires a "special" version of fork() before a setuid() call */ - if ((pid = os_fork(unixd_config.user_name)) == -1) { -#elif defined(TPF) - if ((pid = os_fork(s, slot)) == -1) { -#else - if ((pid = fork()) == -1) { -#endif - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process"); - - /* fork didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, - (request_rec *) NULL); - - /* 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; - } - - if (!pid) { -#ifdef HAVE_BINDPROCESSOR - /* by default AIX binds to a single processor - * this bit unbinds children which will then bind to another cpu - */ - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, - ap_server_conf, "processor unbind failed %d", status); - } -#endif - RAISE_SIGSTOP(MAKE_CHILD); - AP_MONCONTROL(1); - /* Disable the parent's signal handlers and set up proper handling in - * the child. - */ - apr_signal(SIGHUP, just_die); - apr_signal(SIGTERM, just_die); - /* The child process doesn't do anything for AP_SIG_GRACEFUL. - * Instead, the pod is used for signalling graceful restart. - */ - apr_signal(AP_SIG_GRACEFUL, SIG_IGN); - child_main(slot); - } - - ap_scoreboard_image->parent[slot].pid = pid; - - return 0; -} - - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * idle_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 idle_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(apr_pool_t *p) -{ - int i; - int to_kill; - int idle_count; - worker_score *ws; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - - /* initialize the free_list */ - free_length = 0; - - to_kill = -1; - idle_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - for (i = 0; i < ap_daemons_limit; ++i) { - int status; - - if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate) - break; - ws = &ap_scoreboard_image->servers[i][0]; - status = ws->status; - if (status == SERVER_DEAD) { - /* try to keep children numbers as low as possible */ - if (free_length < idle_spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else { - /* We consider a starting server as idle because we started it - * at least a cycle ago, and if it still hasn't finished starting - * then we're just going to swamp things worse by forking more. - * So we hopefully won't need to fork more if we count it. - * This depends on the ordering of SERVER_READY and SERVER_STARTING. - */ - if (status <= SERVER_READY) { - ++ idle_count; - /* always kill the highest numbered child if we have to... - * no really well thought out reason ... other than observing - * the server behaviour under linux where lower numbered children - * tend to service more hits (and hence are more likely to have - * their data in cpu caches). - */ - to_kill = i; - } - - ++total_non_dead; - last_non_dead = i; - } - } - ap_max_daemons_limit = last_non_dead + 1; - if (idle_count > ap_daemons_max_free) { - /* kill off one child... we use the pod because that'll cause it to - * shut down gracefully, in case it happened to pick up a request - * while we were counting - */ - ap_mpm_pod_signal(pod); - idle_spawn_rate = 1; - } - else if (idle_count < ap_daemons_min_free) { - /* terminate the free list */ - if (free_length == 0) { - /* only report this condition once */ - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "server reached MaxClients setting, consider" - " raising the MaxClients setting"); - reported = 1; - } - idle_spawn_rate = 1; - } - else { - if (idle_spawn_rate >= 8) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "server seems busy, (you may need " - "to increase StartServers, or Min/MaxSpareServers), " - "spawning %d children, there are %d idle, and " - "%d total children", idle_spawn_rate, - idle_count, total_non_dead); - } - for (i = 0; i < free_length; ++i) { -#ifdef TPF - if (make_child(ap_server_conf, free_slots[i]) == -1) { - if(free_length == 1) { - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, ap_server_conf, - "No active child processes: shutting down"); - } - } -#else - make_child(ap_server_conf, free_slots[i]); -#endif /* TPF */ - } - /* 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 (idle_spawn_rate < MAX_SPAWN_RATE) { - idle_spawn_rate *= 2; - } - } - } - else { - idle_spawn_rate = 1; - } -} - -/***************************************************************** - * Executive routines. - */ - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int index; - int remaining_children_to_start; - apr_status_t rv; - - ap_log_pid(pconf, ap_pid_fname); - - first_server_limit = server_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - - /* Initialize cross-process accept lock */ - ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, - ap_server_root_relative(_pconf, ap_lock_fname), - ap_my_pid); - - rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname, - ap_accept_lock_mech, _pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create accept lock"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - -#if APR_USE_SYSVSEM_SERIALIZE - if (ap_accept_lock_mech == APR_LOCK_DEFAULT || - ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#else - if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#endif - rv = unixd_set_proc_mutex_perms(accept_mutex); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't set permissions on cross-process lock; " - "check User and Group directives"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - } - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - /* fix the generation number in the global score; we just got a new, - * cleared scoreboard - */ - ap_scoreboard_image->global->running_generation = ap_my_generation; - } - - set_signals(); - - if (one_process) { - AP_MONCONTROL(1); - } - - if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */ - ap_daemons_max_free = ap_daemons_min_free + 1; - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least daemons_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_children_to_start = ap_daemons_to_start; - if (remaining_children_to_start > ap_daemons_limit) { - remaining_children_to_start = ap_daemons_limit; - } - if (!is_graceful) { - startup_children(remaining_children_to_start); - remaining_children_to_start = 0; - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(accept_mutex), - apr_proc_mutex_defname()); -#endif - restart_pending = shutdown_pending = 0; - - mpm_state = AP_MPMQ_RUNNING; - - while (!restart_pending && !shutdown_pending) { - int child_slot; - apr_exit_why_e exitwhy; - int status, processed_status; - /* this is a memory leak, but I'll fix it later. */ - apr_proc_t pid; - - ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); - - /* XXX: if it takes longer than 1 second for all our children - * to start up and get into IDLE state then we may spawn an - * extra child - */ - if (pid.pid != -1) { - processed_status = ap_process_child_status(&pid, exitwhy, status); - if (processed_status == APEXIT_CHILDFATAL) { - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - - /* non-fatal death... note that it's gone in the scoreboard. */ - child_slot = find_child_by_pid(&pid); - if (child_slot >= 0) { - (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD, - (request_rec *) NULL); - if (processed_status == APEXIT_CHILDSICK) { - /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc) - * cut the fork rate to the minimum - */ - idle_spawn_rate = 1; - } - else if (remaining_children_to_start - && child_slot < ap_daemons_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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_WARNING, - 0, ap_server_conf, - "long lost child came home! (pid %ld)", (long)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_children_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_children(remaining_children_to_start); - remaining_children_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(pconf); -#ifdef TPF - shutdown_pending = os_check_server(tpf_server_name); - ap_check_signals(); - sleep(1); -#endif /*TPF */ - } - - mpm_state = AP_MPMQ_STOPPING; - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with 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_INFO, - 0, ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "Graceful restart requested, doing restart"); - - /* kill off the idle ones */ - ap_mpm_pod_killpg(pod, ap_max_daemons_limit); - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. This will break - * in a very nasty way if we ever have the scoreboard totally - * file-based (no shared memory) - */ - for (index = 0; index < ap_daemons_limit; ++index) { - if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { - ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL; - } - } - } - else { - /* Kill 'em off */ - if (unixd_killpg(getpgrp(), SIGHUP) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP"); - } - ap_reclaim_child_processes(0); /* Not when just starting up */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - return 0; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - apr_status_t rv; - - pconf = p; - ap_server_conf = s; - - if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - - if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); - return DONE; - } - return OK; -} - -static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach, debug, foreground; - apr_status_t rv; - - mpm_state = AP_MPMQ_STARTING; - - debug = ap_exists_config_define("DEBUG"); - - if (debug) { - foreground = one_process = 1; - no_detach = 0; - } - else - { - no_detach = ap_exists_config_define("NO_DETACH"); - one_process = ap_exists_config_define("ONE_PROCESS"); - foreground = ap_exists_config_define("FOREGROUND"); - } - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !foreground) { - rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND - : APR_PROC_DETACH_DAEMONIZE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "apr_proc_detach failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - - parent_pid = ap_my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_START_DAEMON; - ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON; - ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON; - ap_daemons_limit = server_limit; - ap_pid_fname = DEFAULT_PIDLOG; - ap_lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static void prefork_hooks(apr_pool_t *p) -{ - /* The prefork open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - -#ifdef AUX3 - (void) set42sig(); -#endif - - ap_hook_open_logs(prefork_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); - /* we need to set the MPM state before other pre-config hooks use MPM query - * to retrieve it, so register as REALLY_FIRST - */ - ap_hook_pre_config(prefork_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); -} - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_min_free = atoi(arg); - if (ap_daemons_min_free <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareServers set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - ap_daemons_min_free = 1; - } - - return NULL; -} - -static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_max_free = atoi(arg); - return NULL; -} - -static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_limit = atoi(arg); - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d exceeds ServerLimit value " - "of %d servers,", ap_daemons_limit, server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the ServerLimit", server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_server_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } - return NULL; -} - -static const command_rec prefork_cmds[] = { -UNIX_DAEMON_COMMANDS, -LISTEN_COMMANDS, -AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, - "Maximum number of idle children"), -AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, - "Maximum number of children alive at the same time"), -AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, - "Maximum value of MaxClients for this run of Apache"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_prefork_module = { - MPM20_MODULE_STUFF, - ap_mpm_rewrite_args, /* 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 */ - prefork_cmds, /* command apr_table_t */ - prefork_hooks, /* register hooks */ -}; diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c deleted file mode 100644 index a352dd1b..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c +++ /dev/null @@ -1,697 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef WIN32 - -/* - * Win9xConHook.dll - a hook proc to clean up Win95/98 console behavior. - * - * It is well(?) documented by Microsoft that the Win9x HandlerRoutine - * hooked by the SetConsoleCtrlHandler never receives the CTRL_CLOSE_EVENT, - * CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT signals. - * - * It is possible to have a second window to monitor the WM_ENDSESSION - * message, but the close button still fails.. - * - * There is a 16bit polling method for the close window option, but this - * is CPU intensive and requires thunking. - * - * Attempts to subclass the 'tty' console fail, since that message thread - * is actually owned by the 16 bit winoldap.mod process, although the - * window reports it is owned by the process/thread of the console app. - * - * Win9xConHook is thunks the WM_CLOSE and WM_ENDSESSION messages, - * first through a window hook procedure in the winoldap context, into - * a subclass WndProc, and on to a second hidden monitor window in the - * console application's context that dispatches them to the console app's - * registered HandlerRoutine. - */ - -/* This debugging define turns on output to COM1, although you better init - * the port first (even using hyperterm). It's the only way to catch the - * goings on within system logoff/shutdown. - * #define DBG 1 - */ - -#include <windows.h> - -/* Variables used within any process context: - * hookwndmsg is a shared message to send Win9xConHook signals - * origwndprop is a wndprop atom to store the orig wndproc of the tty - * hookwndprop is a wndprop atom to store the hwnd of the hidden child - * is_service reminds us to unmark this process on the way out - */ -static UINT hookwndmsg = 0; -static LPCTSTR origwndprop; -static LPCTSTR hookwndprop; -static BOOL is_service = 0; -//static HMODULE hmodThis = NULL; - -/* Variables used within the tty processes' context: - * is_tty flags this process; -1 == unknown, 1 == if tty, 0 == if not - * hw_tty is the handle of the top level tty in this process context - * is_subclassed is toggled to assure DllMain removes the subclass on unload - * hmodLock is there to try and prevent this dll from being unloaded if the - * hook is removed while we are subclassed - */ -static int is_tty = -1; -static HWND hwtty = NULL; -static BOOL is_subclassed = 0; - -// This simply causes a gpfault the moment it tries to FreeLibrary within -// the subclass procedure ... not good. -//static HMODULE hmodLock = NULL; - -/* Variables used within the service or console app's context: - * hmodHook is the instance handle of this module for registering the hooks - * hhkGetMessage is the hook handle for catching Posted messages - * hhkGetMessage is the hook handle for catching Sent messages - * monitor_hwnd is the invisible window that handles our tty messages - * the tty_info strucure is used to pass args into the hidden window's thread - */ -static HMODULE hmodHook = NULL; -static HHOOK hhkGetMessage; -//static HHOOK hhkCallWndProc; -static HWND monitor_hwnd = NULL; - -typedef struct { - PHANDLER_ROUTINE phandler; - HINSTANCE instance; - HWND parent; - INT type; - LPCSTR name; -} tty_info; - -/* These are the GetWindowLong offsets for the hidden window's internal info - * gwltty_phandler is the address of the app's HandlerRoutine - * gwltty_ttywnd is the tty this hidden window will handle messages from - */ -#define gwltty_phandler 0 -#define gwltty_ttywnd 4 - -/* Forward declaration prototypes for internal functions - */ -static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd); -static LRESULT WINAPI RegisterWindows9xService(BOOL set_service); -static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam); -static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty); -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam); -static int HookProc(int hc, HWND *hwnd, UINT *msg, - WPARAM *wParam, LPARAM *lParam); -#ifdef DBG -static VOID DbgPrintf(LPTSTR fmt, ...); -#endif - - -/* DllMain is invoked by every process in the entire system that is hooked - * by our window hooks, notably the tty processes' context, and by the user - * who wants tty messages (the app). Keep it light and simple. - */ -BOOL __declspec(dllexport) APIENTRY DllMain(HINSTANCE hModule, ULONG ulReason, - LPVOID pctx) -{ - if (ulReason == DLL_PROCESS_ATTACH) - { - //hmodThis = hModule; - if (!hookwndmsg) { - origwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookOrigProc")); - hookwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookThunkWnd")); - hookwndmsg = RegisterWindowMessage("Win9xConHookMsg"); - } -#ifdef DBG -// DbgPrintf("H ProcessAttach:%8.8x\r\n", -// GetCurrentProcessId()); -#endif - } - else if ( ulReason == DLL_PROCESS_DETACH ) - { -#ifdef DBG -// DbgPrintf("H ProcessDetach:%8.8x\r\n", GetCurrentProcessId()); -#endif - if (monitor_hwnd) - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - if (is_subclassed) - SendMessage(hwtty, hookwndmsg, 0, (LPARAM)hwtty); - if (hmodHook) - { - if (hhkGetMessage) { - UnhookWindowsHookEx(hhkGetMessage); - hhkGetMessage = NULL; - } - //if (hhkCallWndProc) { - // UnhookWindowsHookEx(hhkCallWndProc); - // hhkCallWndProc = NULL; - //} - FreeLibrary(hmodHook); - hmodHook = NULL; - } - if (is_service) - RegisterWindows9xService(FALSE); - if (hookwndmsg) { - GlobalDeleteAtom((ATOM)origwndprop); - GlobalDeleteAtom((ATOM)hookwndprop); - hookwndmsg = 0; - } - } - return TRUE; -} - - -/* This group of functions are provided for the service/console app - * to register itself a HandlerRoutine to accept tty or service messages - */ - - -/* Exported function that creates a Win9x 'service' via a hidden window, - * that notifies the process via the HandlerRoutine messages. - */ -BOOL __declspec(dllexport) WINAPI Windows9xServiceCtrlHandler( - PHANDLER_ROUTINE phandler, - LPCSTR name) -{ - /* If we have not yet done so */ - FreeConsole(); - - if (name) - { - DWORD tid; - HANDLE hThread; - /* NOTE: this is static so the module can continue to - * access these args while we go on to other things - */ - static tty_info tty; - tty.instance = GetModuleHandle(NULL); - tty.phandler = phandler; - tty.parent = NULL; - tty.name = name; - tty.type = 2; - RegisterWindows9xService(TRUE); - hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread, - (LPVOID)&tty, 0, &tid); - if (hThread) - { - CloseHandle(hThread); - return TRUE; - } - } - else /* remove */ - { - if (monitor_hwnd) - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - RegisterWindows9xService(FALSE); - return TRUE; - } - return FALSE; -} - - -/* Exported function that registers a HandlerRoutine to accept missing - * Win9x CTRL_EVENTs from the tty window, as NT does without a hassle. - * If add is 1 or 2, register the handler, if 2 also mark it as a service. - * If add is 0 deregister the handler, and unmark if a service - */ -BOOL __declspec(dllexport) WINAPI FixConsoleCtrlHandler( - PHANDLER_ROUTINE phandler, - INT add) -{ - HWND parent; - - if (add) - { - HANDLE hThread; - DWORD tid; - /* NOTE: this is static so the module can continue to - * access these args while we go on to other things - */ - static tty_info tty; - EnumWindows(EnumttyWindow, (LPARAM)&parent); - if (!parent) { -#ifdef DBG - DbgPrintf("A EnumttyWindow failed (%d)\r\n", GetLastError()); -#endif - return FALSE; - } - tty.instance = GetModuleHandle(NULL); - tty.phandler = phandler; - tty.parent = parent; - tty.type = add; - if (add == 2) { - tty.name = "ttyService"; - RegisterWindows9xService(TRUE); - } - else - tty.name = "ttyMonitor"; - hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread, - (LPVOID)&tty, 0, &tid); - if (!hThread) - return FALSE; - CloseHandle(hThread); - hmodHook = LoadLibrary("Win9xConHook.dll"); - if (hmodHook) - { - hhkGetMessage = SetWindowsHookEx(WH_GETMESSAGE, - (HOOKPROC)GetProcAddress(hmodHook, "GetMsgProc"), hmodHook, 0); - //hhkCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, - // (HOOKPROC)GetProcAddress(hmodHook, "CallWndProc"), hmodHook, 0); - } - return TRUE; - } - else /* remove */ - { - if (monitor_hwnd) { - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - } - if (hmodHook) - { - if (hhkGetMessage) { - UnhookWindowsHookEx(hhkGetMessage); - hhkGetMessage = NULL; - } - //if (hhkCallWndProc) { - // UnhookWindowsHookEx(hhkCallWndProc); - // hhkCallWndProc = NULL; - //} - FreeLibrary(hmodHook); - hmodHook = NULL; - } - if (is_service) - RegisterWindows9xService(FALSE); - return TRUE; - } - return FALSE; -} - - -/* The following internal helpers are only used within the app's context - */ - -/* ttyConsoleCreateThread is the process that runs within the user app's - * context. It creates and pumps the messages of a hidden monitor window, - * watching for messages from the system, or the associated subclassed tty - * window. Things can happen in our context that can't be done from the - * tty's context, and visa versa, so the subclass procedure and this hidden - * window work together to make it all happen. - */ -static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty) -{ - WNDCLASS wc; - MSG msg; - wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = ttyConsoleCtrlWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 8; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - if (((tty_info*)tty)->parent) - wc.lpszClassName = "ttyConHookChild"; - else - wc.lpszClassName = "ApacheWin95ServiceMonitor"; - - if (!RegisterClass(&wc)) { -#ifdef DBG - DbgPrintf("A proc %8.8x Error creating class %s (%d)\r\n", - GetCurrentProcessId(), wc.lpszClassName, GetLastError()); -#endif - return 0; - } - - /* Create an invisible window */ - monitor_hwnd = CreateWindow(wc.lpszClassName, ((tty_info*)tty)->name, - WS_OVERLAPPED & ~WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, - ((tty_info*)tty)->instance, tty); - - if (!monitor_hwnd) { -#ifdef DBG - DbgPrintf("A proc %8.8x Error creating window %s %s (%d)\r\n", - GetCurrentProcessId(), wc.lpszClassName, - ((tty_info*)tty)->name, GetLastError()); -#endif - return 0; - } - - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - /* Tag again as deleted, just in case we missed WM_DESTROY */ - monitor_hwnd = NULL; - return 0; -} - - -/* This is the WndProc procedure for our invisible window. - * When our subclasssed tty window receives the WM_CLOSE, WM_ENDSESSION, - * or WM_QUERYENDSESSION messages, the message is dispatched to our hidden - * window (this message process), and we call the installed HandlerRoutine - * that was registered by the app. - */ -static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_CREATE) - { - tty_info *tty = (tty_info*)(((LPCREATESTRUCT)lParam)->lpCreateParams); - SetWindowLong(hwnd, gwltty_phandler, (LONG)tty->phandler); - SetWindowLong(hwnd, gwltty_ttywnd, (LONG)tty->parent); -#ifdef DBG - DbgPrintf("A proc %8.8x created %8.8x %s for tty wnd %8.8x\r\n", - GetCurrentProcessId(), hwnd, - tty->name, tty->parent); -#endif - if (tty->parent) { - SetProp(tty->parent, hookwndprop, hwnd); - PostMessage(tty->parent, hookwndmsg, - tty->type, (LPARAM)tty->parent); - } - return 0; - } - else if (msg == WM_DESTROY) - { - HWND parent = (HWND)GetWindowLong(hwnd, gwltty_ttywnd); -#ifdef DBG - DbgPrintf("A proc %8.8x destroyed %8.8x ttyConHookChild\r\n", - GetCurrentProcessId(), hwnd); -#endif - if (parent) { - RemoveProp(parent, hookwndprop); - SendMessage(parent, hookwndmsg, 0, (LPARAM)parent); - } - monitor_hwnd = NULL; - } - else if (msg == WM_CLOSE) - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_CLOSE_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_CLOSE_EVENT " - "returning %d\r\n", - GetCurrentProcessId(), rv); -#endif - if (rv) - return !rv; - } - else if ((msg == WM_QUERYENDSESSION) || (msg == WM_ENDSESSION)) - { - if (lParam & ENDSESSION_LOGOFF) - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_LOGOFF_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_LOGOFF_EVENT " - "returning %d\r\n", - GetCurrentProcessId(), rv); -#endif - if (rv) - return ((msg == WM_QUERYENDSESSION) ? rv : !rv); - } - else - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_SHUTDOWN_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_SHUTDOWN_EVENT " - "returning %d\r\n", GetCurrentProcessId(), rv); -#endif - if (rv) - return ((msg == WM_QUERYENDSESSION) ? rv : !rv); - } - } - return (DefWindowProc(hwnd, msg, wParam, lParam)); -} - - -/* The following internal helpers are invoked by the hooked tty and our app - */ - - -/* Register or deregister the current process as a Windows9x style service. - * Experience shows this call is ignored across processes, so the second - * arg to RegisterServiceProcess (process group id) is effectively useless. - */ -static LRESULT WINAPI RegisterWindows9xService(BOOL set_service) -{ - static HINSTANCE hkernel; - static DWORD (WINAPI *register_service_process)(DWORD, DWORD) = NULL; - BOOL rv; - - if (set_service == is_service) - return 1; - -#ifdef DBG - DbgPrintf("R %s proc %8.8x as a service\r\n", - set_service ? "installing" : "removing", - GetCurrentProcessId()); -#endif - - if (!register_service_process) - { - /* Obtain a handle to the kernel library */ - hkernel = LoadLibrary("KERNEL32.DLL"); - if (!hkernel) - return 0; - - /* Find the RegisterServiceProcess function */ - register_service_process = (DWORD (WINAPI *)(DWORD, DWORD)) - GetProcAddress(hkernel, "RegisterServiceProcess"); - if (register_service_process == NULL) { - FreeLibrary(hkernel); - return 0; - } - } - - /* Register this process as a service */ - rv = register_service_process(0, set_service != FALSE); - if (rv) - is_service = set_service; - - if (!is_service) - { - /* Unload the kernel library */ - FreeLibrary(hkernel); - register_service_process = NULL; - } - return rv; -} - - -/* - * This function only works when this process is the active process - * (e.g. once it is running a child process, it can no longer determine - * which console window is its own.) - */ -static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd) -{ - char tmp[8]; - if (GetClassName(wnd, tmp, sizeof(tmp)) && !strcmp(tmp, "tty")) - { - DWORD wndproc, thisproc = GetCurrentProcessId(); - GetWindowThreadProcessId(wnd, &wndproc); - if (wndproc == thisproc) { - *((HWND*)retwnd) = wnd; - return FALSE; - } - } - return TRUE; -} - - -/* The remaining code all executes --in the tty's own process context-- - * - * That means special attention must be paid to what it's doing... - */ - -/* Subclass message process for the tty window - * - * This code -handles- WM_CLOSE, WM_ENDSESSION and WM_QUERYENDSESSION - * by dispatching them to the window identified by the hookwndprop - * property atom set against our window. Messages are then dispatched - * to origwndprop property atom we set against the window when we - * injected this subclass. This trick did not work with simply a hook. - */ -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - WNDPROC origproc = (WNDPROC) GetProp(hwnd, origwndprop); - if (!origproc) - return 0; - - if (msg == WM_NCDESTROY - || (msg == hookwndmsg && !LOWORD(wParam) && (HWND)lParam == hwnd)) - { - if (is_subclassed) { -#ifdef DBG - DbgPrintf("W proc %08x hwnd:%08x Subclass removed\r\n", - GetCurrentProcessId(), hwnd); -#endif - if (is_service) - RegisterWindows9xService(FALSE); - SetWindowLong(hwnd, GWL_WNDPROC, (LONG)origproc); - RemoveProp(hwnd, origwndprop); - RemoveProp(hwnd, hookwndprop); - is_subclassed = FALSE; - //if (hmodLock) - // FreeLibrary(hmodLock); - //hmodLock = NULL; - } - } - else if (msg == WM_CLOSE || msg == WM_ENDSESSION - || msg == WM_QUERYENDSESSION) - { - HWND child = (HWND)GetProp(hwnd, hookwndprop); - if (child) { -#ifdef DBG - DbgPrintf("W proc %08x hwnd:%08x forwarded msg:%d\r\n", - GetCurrentProcessId(), hwnd, msg); -#endif - return SendMessage(child, msg, wParam, lParam); - } - } - return CallWindowProc(origproc, hwnd, msg, wParam, lParam); -} - - -/* HookProc, once installed, is responsible for subclassing the system - * tty windows. It generally does nothing special itself, since - * research indicates that it cannot deal well with the messages we are - * interested in, that is, WM_CLOSE, WM_QUERYSHUTDOWN and WM_SHUTDOWN - * of the tty process. - * - * Respond and subclass only when a WM_NULL is received by the window. - */ -int HookProc(int hc, HWND *hwnd, UINT *msg, WPARAM *wParam, LPARAM *lParam) -{ - if (is_tty == -1 && *hwnd) - { - char ttybuf[8]; - HWND htty; - hwtty = *hwnd; - while (htty = GetParent(hwtty)) - hwtty = htty; - is_tty = (GetClassName(hwtty, ttybuf, sizeof(ttybuf)) - && !strcmp(ttybuf, "tty")); -#ifdef DBG - if (is_tty) - DbgPrintf("H proc %08x tracking hwnd %08x\r\n", - GetCurrentProcessId(), hwtty); -#endif - } - - if (*msg == hookwndmsg && *wParam && *lParam == (LPARAM)hwtty && is_tty) - { - WNDPROC origproc = (WNDPROC)GetWindowLong(hwtty, GWL_WNDPROC); - //char myname[MAX_PATH]; - //if (GetModuleFileName(hmodThis, myname, sizeof(myname))) - // hmodLock = LoadLibrary(myname); - SetProp(hwtty, origwndprop, origproc); - SetWindowLong(hwtty, GWL_WNDPROC, (LONG)WndProc); - is_subclassed = TRUE; -#ifdef DBG - DbgPrintf("H proc %08x hwnd:%08x Subclassed\r\n", - GetCurrentProcessId(), hwtty); -#endif - if (LOWORD(*wParam) == 2) - RegisterWindows9xService(TRUE); - } - - return -1; -} - - -/* - * PostMessage Hook: - */ -LRESULT __declspec(dllexport) CALLBACK GetMsgProc(INT hc, WPARAM wParam, - LPARAM lParam) -{ - PMSG pmsg; - - pmsg = (PMSG)lParam; - - if (pmsg) { - int rv = HookProc(hc, &pmsg->hwnd, &pmsg->message, - &pmsg->wParam, &pmsg->lParam); - if (rv != -1) - return rv; - } - /* - * CallNextHookEx apparently ignores the hhook argument, so pass NULL - */ - return CallNextHookEx(NULL, hc, wParam, lParam); -} - - -/* - * SendMessage Hook: - */ -LRESULT __declspec(dllexport) CALLBACK CallWndProc(INT hc, WPARAM wParam, - LPARAM lParam) -{ - PCWPSTRUCT pcwps = (PCWPSTRUCT)lParam; - - if (pcwps) { - int rv = HookProc(hc, &pcwps->hwnd, &pcwps->message, - &pcwps->wParam, &pcwps->lParam); - if (rv != -1) - return rv; - } - /* - * CallNextHookEx apparently ignores the hhook argument, so pass NULL - */ - return CallNextHookEx(NULL, hc, wParam, lParam); -} - - -#ifdef DBG -VOID DbgPrintf( - LPTSTR fmt, - ... - ) -{ - static HANDLE mutex; - va_list marker; - TCHAR szBuf[256]; - DWORD t; - HANDLE gDbgOut; - - va_start(marker, fmt); - wvsprintf(szBuf, fmt, marker); - va_end(marker); - - if (!mutex) - mutex = CreateMutex(NULL, FALSE, "Win9xConHookDbgOut"); - WaitForSingleObject(mutex, INFINITE); - gDbgOut = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); - WriteFile(gDbgOut, szBuf, strlen(szBuf), &t, NULL); - CloseHandle(gDbgOut); - ReleaseMutex(mutex); -} -#endif - -#endif /* WIN32 */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def deleted file mode 100644 index 85ec1664..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def +++ /dev/null @@ -1,10 +0,0 @@ -LIBRARY Win9xConHook - -EXETYPE WINDOWS - -EXPORTS - DllMain - GetMsgProc - CallWndProc - FixConsoleCtrlHandler - Windows9xServiceCtrlHandler diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp deleted file mode 100644 index 77cbacfc..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp +++ /dev/null @@ -1,103 +0,0 @@ -# Microsoft Developer Studio Project File - Name="Win9xConHook" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=Win9xConHook - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Win9xConHook.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Win9xConHook.mak" CFG="Win9xConHook - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Win9xConHook - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Win9xConHook - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Win9xConHook - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\Release" -# PROP BASE Intermediate_Dir ".\Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /Fd"Release\Win9xConHook" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /base:"0x1c0f0000" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /base:"0x1c0f0000" /opt:ref - -!ELSEIF "$(CFG)" == "Win9xConHook - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /Fd"Debug\Win9xConHook" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /debug /base:"0x1c0f0000" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /debug /base:"0x1c0f0000" - -!ENDIF - -# Begin Target - -# Name "Win9xConHook - Win32 Release" -# Name "Win9xConHook - Win32 Debug" -# Begin Source File - -SOURCE=.\Win9xConHook.c -# End Source File -# Begin Source File - -SOURCE=.\Win9xConHook.def -# End Source File -# Begin Source File - -SOURCE=.\Win9xConHook.h -# End Source File -# End Target -# End Project diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h deleted file mode 100644 index e3471034..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AP_WIN9XCONHOOK_H -#define AP_WIN9XCONHOOK_H - -#ifdef WIN32 - -/* Windows9xServiceCtrlHandler registers a handler routine, frees the - * console window, and registers this process as a service in Win9x. - * It creats a hidden window of class "ApacheWin95ServiceMonitor" - * and titled by the name passed, which passes the WM_SHUTDOWN message - * through the given HandlerRoutine's CTRL_SHUTDOWN event. - * Call with name of NULL to remove the Service handler. - */ -BOOL WINAPI Windows9xServiceCtrlHandler(PHANDLER_ROUTINE phandler, LPCSTR name); - - -/* FixConsoleControlHandler registers a handler routine with the - * Win9xConHook.dll, creating a hidden window and forwarding the - * WM_ENDSESSION and WM_CLOSE messages to the given HandlerRoutine - * as CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT and CTRL_CLOSE_EVENT. - * The application should still use SetConsoleCtrlHandler to grab - * the CTRL_BREAK_EVENT and CTRL_C_EVENT, if desired. - */ -BOOL WINAPI FixConsoleCtrlHandler(PHANDLER_ROUTINE phandler, BOOL add); - - -/* - * Exported PostMessage Hook, never use this directly: - * - * LRESULT CALLBACK GetMsgProc(INT hc, WPARAM wParam, LPARAM lParam); - */ - - -/* - * Exported SendMessage Hook, never use this directly: - * - * LRESULT CALLBACK CallWndProc(INT hc, WPARAM wParam, LPARAM lParam); - */ - -#endif /* WIN32 */ - -#endif AP_WIN9XCONHOOK_H diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c deleted file mode 100644 index 266d0b3c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c +++ /dev/null @@ -1,1167 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef WIN32 - -#define CORE_PRIVATE -#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 "apr_portable.h" -#include "apr_thread_proc.h" -#include "apr_getopt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_shm.h" -#include "apr_thread_mutex.h" -#include "ap_mpm.h" -#include "ap_config.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm_winnt.h" -#include "mpm_common.h" -#include <malloc.h> -#include "apr_atomic.h" - -/* shared with mpm_winnt.c */ -extern DWORD my_pid; - -/* used by parent to signal the child to start and exit */ -/* shared with mpm_winnt.c, but should be private to child.c */ -apr_proc_mutex_t *start_mutex; -HANDLE exit_event; - -/* child_main() should never need to modify is_graceful!?! */ -extern int volatile is_graceful; - -/* Queue for managing the passing of COMP_CONTEXTs between - * the accept and worker threads. - */ -static apr_pool_t *pchild; -static int shutdown_in_progress = 0; -static int workers_may_exit = 0; -static unsigned int g_blocked_threads = 0; -static HANDLE max_requests_per_child_event; - -static apr_thread_mutex_t *child_lock; -static apr_thread_mutex_t *qlock; -static PCOMP_CONTEXT qhead = NULL; -static PCOMP_CONTEXT qtail = NULL; -static int num_completion_contexts = 0; -static int max_num_completion_contexts = 0; -static HANDLE ThreadDispatchIOCP = NULL; -static HANDLE qwait_event = NULL; - - -AP_DECLARE(void) mpm_recycle_completion_context(PCOMP_CONTEXT context) -{ - /* Recycle the completion context. - * - clear the ptrans pool - * - put the context on the queue to be consumed by the accept thread - * Note: - * context->accept_socket may be in a disconnected but reusable - * state so -don't- close it. - */ - if (context) { - apr_pool_clear(context->ptrans); - context->ba = apr_bucket_alloc_create(context->ptrans); - context->next = NULL; - ResetEvent(context->Overlapped.hEvent); - apr_thread_mutex_lock(qlock); - if (qtail) { - qtail->next = context; - } else { - qhead = context; - SetEvent(qwait_event); - } - qtail = context; - apr_thread_mutex_unlock(qlock); - } -} - -AP_DECLARE(PCOMP_CONTEXT) mpm_get_completion_context(void) -{ - apr_status_t rv; - PCOMP_CONTEXT context = NULL; - - while (1) { - /* Grab a context off the queue */ - apr_thread_mutex_lock(qlock); - if (qhead) { - context = qhead; - qhead = qhead->next; - if (!qhead) - qtail = NULL; - } else { - ResetEvent(qwait_event); - } - apr_thread_mutex_unlock(qlock); - - if (!context) { - /* We failed to grab a context off the queue, consider allocating - * a new one out of the child pool. There may be up to - * (ap_threads_per_child + num_listeners) contexts in the system - * at once. - */ - if (num_completion_contexts >= max_num_completion_contexts) { - /* All workers are busy, need to wait for one */ - static int reported = 0; - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, - "Server ran out of threads to serve requests. Consider " - "raising the ThreadsPerChild setting"); - reported = 1; - } - - /* Wait for a worker to free a context. Once per second, give - * the caller a chance to check for shutdown. If the wait - * succeeds, get the context off the queue. It must be available, - * since there's only one consumer. - */ - rv = WaitForSingleObject(qwait_event, 1000); - if (rv == WAIT_OBJECT_0) - continue; - else /* Hopefully, WAIT_TIMEOUT */ - return NULL; - } else { - /* Allocate another context. - * Note: - * Multiple failures in the next two steps will cause the pchild pool - * to 'leak' storage. I don't think this is worth fixing... - */ - apr_allocator_t *allocator; - - apr_thread_mutex_lock(child_lock); - context = (PCOMP_CONTEXT) apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); - - context->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (context->Overlapped.hEvent == NULL) { - /* Hopefully this is a temporary condition ... */ - ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_os_error(), ap_server_conf, - "mpm_get_completion_context: CreateEvent failed."); - - apr_thread_mutex_unlock(child_lock); - return NULL; - } - - /* Create the tranaction pool */ - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - rv = apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_WARNING, rv, ap_server_conf, - "mpm_get_completion_context: Failed to create the transaction pool."); - CloseHandle(context->Overlapped.hEvent); - - apr_thread_mutex_unlock(child_lock); - return NULL; - } - apr_allocator_owner_set(allocator, context->ptrans); - apr_pool_tag(context->ptrans, "transaction"); - context->accept_socket = INVALID_SOCKET; - context->ba = apr_bucket_alloc_create(context->ptrans); - apr_atomic_inc(&num_completion_contexts); - - apr_thread_mutex_unlock(child_lock); - break; - } - } else { - /* Got a context from the queue */ - break; - } - } - - return context; -} - -AP_DECLARE(apr_status_t) mpm_post_completion_context(PCOMP_CONTEXT context, - io_state_e state) -{ - LPOVERLAPPED pOverlapped; - if (context) - pOverlapped = &context->Overlapped; - else - pOverlapped = NULL; - - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, state, pOverlapped); - return APR_SUCCESS; -} - - -/* - * find_ready_listener() - * Only used by Win9* and should go away when the win9*_accept() function is - * reimplemented using apr_poll(). - */ -static ap_listen_rec *head_listener; - -static APR_INLINE ap_listen_rec *find_ready_listener(fd_set * main_fds) -{ - ap_listen_rec *lr; - SOCKET nsd; - - lr = head_listener; - do { - apr_os_sock_get(&nsd, lr->sd); - if (FD_ISSET(nsd, main_fds)) { - head_listener = lr->next; - if (!head_listener) { - head_listener = ap_listeners; - } - return lr; - } - lr = lr->next; - if (!lr) { - lr = ap_listeners; - } - } while (lr != head_listener); - return NULL; -} - - -/* Windows 9x specific code... - * Accept processing for on Windows 95/98 uses a producer/consumer queue - * model. A single thread accepts connections and queues the accepted socket - * to the accept queue for consumption by a pool of worker threads. - * - * win9x_accept() - * The accept threads runs this function, which accepts connections off - * the network and calls add_job() to queue jobs to the accept_queue. - * add_job()/remove_job() - * Add or remove an accepted socket from the list of sockets - * connected to clients. allowed_globals.jobmutex protects - * against multiple concurrent access to the linked list of jobs. - * win9x_get_connection() - * Calls remove_job() to pull a job from the accept queue. All the worker - * threads block on remove_job. - */ - -typedef struct joblist_s { - struct joblist_s *next; - int sock; -} joblist; - -typedef struct globals_s { - HANDLE jobsemaphore; - joblist *jobhead; - joblist *jobtail; - apr_thread_mutex_t *jobmutex; - int jobcount; -} globals; - -globals allowed_globals = {NULL, NULL, NULL, NULL, 0}; - -#define MAX_SELECT_ERRORS 100 - - -static void add_job(int sock) -{ - joblist *new_job; - - new_job = (joblist *) malloc(sizeof(joblist)); - if (new_job == NULL) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Ouch! Out of memory in add_job()!"); - return; - } - new_job->next = NULL; - new_job->sock = sock; - - apr_thread_mutex_lock(allowed_globals.jobmutex); - - if (allowed_globals.jobtail != NULL) - allowed_globals.jobtail->next = new_job; - allowed_globals.jobtail = new_job; - if (!allowed_globals.jobhead) - allowed_globals.jobhead = new_job; - allowed_globals.jobcount++; - ReleaseSemaphore(allowed_globals.jobsemaphore, 1, NULL); - - apr_thread_mutex_unlock(allowed_globals.jobmutex); -} - - -static int remove_job(void) -{ - joblist *job; - int sock; - - WaitForSingleObject(allowed_globals.jobsemaphore, INFINITE); - apr_thread_mutex_lock(allowed_globals.jobmutex); - - if (shutdown_in_progress && !allowed_globals.jobhead) { - apr_thread_mutex_unlock(allowed_globals.jobmutex); - return (INVALID_SOCKET); - } - job = allowed_globals.jobhead; - ap_assert(job); - allowed_globals.jobhead = job->next; - if (allowed_globals.jobhead == NULL) - allowed_globals.jobtail = NULL; - apr_thread_mutex_unlock(allowed_globals.jobmutex); - sock = job->sock; - free(job); - - return (sock); -} - - -static unsigned int __stdcall win9x_accept(void * dummy) -{ - struct timeval tv; - fd_set main_fds; - int wait_time = 1; - int csd; - SOCKET nsd = INVALID_SOCKET; - struct sockaddr_in sa_client; - int count_select_errors = 0; - int rc; - int clen; - ap_listen_rec *lr; - struct fd_set listenfds; - SOCKET listenmaxfd = INVALID_SOCKET; - - /* Setup the listeners - * ToDo: Use apr_poll() - */ - FD_ZERO(&listenfds); - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - apr_os_sock_get(&nsd, lr->sd); - FD_SET(nsd, &listenfds); - if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) { - listenmaxfd = nsd; - } - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "Child %d: Listening on port %d.", my_pid, lr->bind_addr->port); - } - } - - head_listener = ap_listeners; - - while (!shutdown_in_progress) { - tv.tv_sec = wait_time; - tv.tv_usec = 0; - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - - rc = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); - - if (rc == 0 || (rc == SOCKET_ERROR && APR_STATUS_IS_EINTR(apr_get_netos_error()))) { - count_select_errors = 0; /* reset count of errors */ - continue; - } - else if (rc == SOCKET_ERROR) { - /* A "real" error occurred, log it and increment the count of - * select errors. This count is used to ensure we don't go into - * a busy loop of continuous errors. - */ - ap_log_error(APLOG_MARK, APLOG_INFO, apr_get_netos_error(), ap_server_conf, - "select failed with error %d", apr_get_netos_error()); - count_select_errors++; - if (count_select_errors > MAX_SELECT_ERRORS) { - shutdown_in_progress = 1; - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf, - "Too many errors in select loop. Child process exiting."); - break; - } - } else { - ap_listen_rec *lr; - - lr = find_ready_listener(&main_fds); - if (lr != NULL) { - /* fetch the native socket descriptor */ - apr_os_sock_get(&nsd, lr->sd); - } - } - - do { - clen = sizeof(sa_client); - csd = accept(nsd, (struct sockaddr *) &sa_client, &clen); - } while (csd < 0 && APR_STATUS_IS_EINTR(apr_get_netos_error())); - - if (csd < 0) { - if (APR_STATUS_IS_ECONNABORTED(apr_get_netos_error())) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf, - "accept: (client socket)"); - } - } - else { - add_job(csd); - } - } - SetEvent(exit_event); - return 0; -} - - -static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) -{ - apr_os_sock_info_t sockinfo; - int len; - - if (context == NULL) { - /* allocate the completion context and the transaction pool */ - apr_allocator_t *allocator; - apr_thread_mutex_lock(child_lock); - context = apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); - apr_allocator_owner_set(allocator, context->ptrans); - apr_pool_tag(context->ptrans, "transaction"); - apr_thread_mutex_unlock(child_lock); - } - - while (1) { - apr_pool_clear(context->ptrans); - context->ba = apr_bucket_alloc_create(context->ptrans); - context->accept_socket = remove_job(); - if (context->accept_socket == INVALID_SOCKET) { - return NULL; - } - len = sizeof(struct sockaddr); - context->sa_server = apr_palloc(context->ptrans, len); - if (getsockname(context->accept_socket, - context->sa_server, &len)== SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "getsockname failed"); - continue; - } - len = sizeof(struct sockaddr); - context->sa_client = apr_palloc(context->ptrans, len); - if ((getpeername(context->accept_socket, - context->sa_client, &len)) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "getpeername failed"); - memset(&context->sa_client, '\0', sizeof(context->sa_client)); - } - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - return context; - } -} - - -/* Windows NT/2000 specific code... - * Accept processing for on Windows NT uses a producer/consumer queue - * model. An accept thread accepts connections off the network then issues - * PostQueuedCompletionStatus() to awake a thread blocked on the ThreadDispatch - * IOCompletionPort. - * - * winnt_accept() - * One or more accept threads run in this function, each of which accepts - * connections off the network and calls PostQueuedCompletionStatus() to - * queue an io completion packet to the ThreadDispatch IOCompletionPort. - * winnt_get_connection() - * Worker threads block on the ThreadDispatch IOCompletionPort awaiting - * connections to service. - */ -#define MAX_ACCEPTEX_ERR_COUNT 250 -static unsigned int __stdcall winnt_accept(void *lr_) -{ - ap_listen_rec *lr = (ap_listen_rec *)lr_; - apr_os_sock_info_t sockinfo; - PCOMP_CONTEXT context = NULL; - DWORD BytesRead; - SOCKET nlsd; - int rv, err_count = 0; - - apr_os_sock_get(&nlsd, lr->sd); - - while (!shutdown_in_progress) { - if (!context) { - context = mpm_get_completion_context(); - if (!context) { - /* Temporary resource constraint? */ - Sleep(0); - continue; - } - } - - /* Create and initialize the accept socket */ - if (context->accept_socket == INVALID_SOCKET) { - context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (context->accept_socket == INVALID_SOCKET) { - /* Another temporary condition? */ - ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "winnt_accept: Failed to allocate an accept socket. " - "Temporary resource constraint? Try again."); - Sleep(100); - continue; - } - } - - /* AcceptEx on the completion context. The completion context will be - * signaled when a connection is accepted. - */ - if (!AcceptEx(nlsd, context->accept_socket, - context->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &BytesRead, - &context->Overlapped)) { - rv = apr_get_netos_error(); - if ((rv == APR_FROM_OS_ERROR(WSAEINVAL)) || - (rv == APR_FROM_OS_ERROR(WSAENOTSOCK))) { - /* We can get here when: - * 1) the client disconnects early - * 2) TransmitFile does not properly recycle the accept socket (typically - * because the client disconnected) - * 3) there is VPN or Firewall software installed with buggy AcceptEx implementation - * 4) the webserver is using a dynamic address that has changed - */ - ++err_count; - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - if (err_count > MAX_ACCEPTEX_ERR_COUNT) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "Child %d: Encountered too many errors accepting client connections. " - "Possible causes: dynamic address renewal, or incompatible VPN or firewall software. " - "Try using the Win32DisableAcceptEx directive.", my_pid); - err_count = 0; - } - continue; - } - else if ((rv != APR_FROM_OS_ERROR(ERROR_IO_PENDING)) && - (rv != APR_FROM_OS_ERROR(WSA_IO_PENDING))) { - ++err_count; - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - if (err_count > MAX_ACCEPTEX_ERR_COUNT) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "Child %d: Encountered too many errors accepting client connections. " - "Possible causes: Unknown. " - "Try using the Win32DisableAcceptEx directive.", my_pid); - err_count = 0; - } - continue; - } - - /* Wait for pending i/o. - * Wake up once per second to check for shutdown . - * XXX: We should be waiting on exit_event instead of polling - */ - while (1) { - rv = WaitForSingleObject(context->Overlapped.hEvent, 1000); - if (rv == WAIT_OBJECT_0) { - if (context->accept_socket == INVALID_SOCKET) { - /* socket already closed */ - break; - } - if (!GetOverlappedResult((HANDLE)context->accept_socket, - &context->Overlapped, - &BytesRead, FALSE)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, - apr_get_os_error(), ap_server_conf, - "winnt_accept: Asynchronous AcceptEx failed."); - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - } - break; - } - /* WAIT_TIMEOUT */ - if (shutdown_in_progress) { - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - break; - } - } - if (context->accept_socket == INVALID_SOCKET) { - continue; - } - } - - err_count = 0; - /* Inherit the listen socket settings. Required for - * shutdown() to work - */ - if (setsockopt(context->accept_socket, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, (char *)&nlsd, - sizeof(nlsd))) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed."); - /* Not a failure condition. Keep running. */ - } - - /* Get the local & remote address */ - GetAcceptExSockaddrs(context->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &context->sa_server, - &context->sa_server_len, - &context->sa_client, - &context->sa_client_len); - - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - /* When a connection is received, send an io completion notification to - * the ThreadDispatchIOCP. This function could be replaced by - * mpm_post_completion_context(), but why do an extra function call... - */ - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_CONNECTION_ACCEPTED, - &context->Overlapped); - context = NULL; - } - if (!shutdown_in_progress) { - /* Yow, hit an irrecoverable error! Tell the child to die. */ - SetEvent(exit_event); - } - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Child %d: Accept thread exiting.", my_pid); - return 0; -} - - -static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context) -{ - int rc; - DWORD BytesRead; - DWORD CompKey; - LPOVERLAPPED pol; - - mpm_recycle_completion_context(context); - - apr_atomic_inc(&g_blocked_threads); - while (1) { - if (workers_may_exit) { - apr_atomic_dec(&g_blocked_threads); - return NULL; - } - rc = GetQueuedCompletionStatus(ThreadDispatchIOCP, &BytesRead, &CompKey, - &pol, INFINITE); - if (!rc) { - rc = apr_get_os_error(); - ap_log_error(APLOG_MARK,APLOG_DEBUG, rc, ap_server_conf, - "Child %d: GetQueuedComplationStatus returned %d", my_pid, rc); - continue; - } - - switch (CompKey) { - case IOCP_CONNECTION_ACCEPTED: - context = CONTAINING_RECORD(pol, COMP_CONTEXT, Overlapped); - break; - case IOCP_SHUTDOWN: - apr_atomic_dec(&g_blocked_threads); - return NULL; - default: - apr_atomic_dec(&g_blocked_threads); - return NULL; - } - break; - } - apr_atomic_dec(&g_blocked_threads); - - return context; -} - - -/* - * worker_main() - * Main entry point for the worker threads. Worker threads block in - * win*_get_connection() awaiting a connection to service. - */ -static unsigned int __stdcall worker_main(void *thread_num_val) -{ - static int requests_this_child = 0; - PCOMP_CONTEXT context = NULL; - int thread_num = (int)thread_num_val; - ap_sb_handle_t *sbh; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, - "Child %d: Worker thread %ld starting.", my_pid, thread_num); - while (1) { - conn_rec *c; - apr_int32_t disconnected; - - ap_update_child_status_from_indexes(0, thread_num, SERVER_READY, NULL); - - /* Grab a connection off the network */ - if (use_acceptex) { - context = winnt_get_connection(context); - } - else { - context = win9x_get_connection(context); - } - if (!context) { - /* Time for the thread to exit */ - break; - } - - /* Have we hit MaxRequestPerChild connections? */ - if (ap_max_requests_per_child) { - requests_this_child++; - if (requests_this_child > ap_max_requests_per_child) { - SetEvent(max_requests_per_child_event); - } - } - - ap_create_sb_handle(&sbh, context->ptrans, 0, thread_num); - c = ap_run_create_connection(context->ptrans, ap_server_conf, - context->sock, thread_num, sbh, - context->ba); - - if (c) { - ap_process_connection(c, context->sock); - apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, - &disconnected); - if (!disconnected) { - context->accept_socket = INVALID_SOCKET; - ap_lingering_close(c); - } - else if (!use_acceptex) { - /* If the socket is disconnected but we are not using acceptex, - * we cannot reuse the socket. Disconnected sockets are removed - * from the apr_socket_t struct by apr_sendfile() to prevent the - * socket descriptor from being inadvertently closed by a call - * to apr_socket_close(), so close it directly. - */ - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - } - } - else { - /* ap_run_create_connection closes the socket on failure */ - context->accept_socket = INVALID_SOCKET; - } - } - - ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD, - (request_rec *) NULL); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, - "Child %d: Worker thread %ld exiting.", my_pid, thread_num); - return 0; -} - - -static void cleanup_thread(HANDLE *handles, int *thread_cnt, int thread_to_clean) -{ - int i; - - CloseHandle(handles[thread_to_clean]); - for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++) - handles[i] = handles[i + 1]; - (*thread_cnt)--; -} - - -/* - * child_main() - * Entry point for the main control thread for the child process. - * This thread creates the accept thread, worker threads and - * monitors the child process for maintenance and shutdown - * events. - */ -static void create_listener_thread() -{ - int tid; - int num_listeners = 0; - if (!use_acceptex) { - _beginthreadex(NULL, 0, win9x_accept, - NULL, 0, &tid); - } else { - /* Start an accept thread per listener - * XXX: Why would we have a NULL sd in our listeners? - */ - ap_listen_rec *lr; - - /* Number of completion_contexts allowed in the system is - * (ap_threads_per_child + num_listeners). We need the additional - * completion contexts to prevent server hangs when ThreadsPerChild - * is configured to something less than or equal to the number - * of listeners. This is not a usual case, but people have - * encountered it. - * */ - for (lr = ap_listeners; lr ; lr = lr->next) { - num_listeners++; - } - max_num_completion_contexts = ap_threads_per_child + num_listeners; - - /* Now start a thread per listener */ - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - _beginthreadex(NULL, 1000, winnt_accept, - (void *) lr, 0, &tid); - } - } - } -} - - -void child_main(apr_pool_t *pconf) -{ - apr_status_t status; - apr_hash_t *ht; - ap_listen_rec *lr; - HANDLE child_events[2]; - HANDLE *child_handles; - int listener_started = 0; - int threads_created = 0; - int watch_thread; - int time_remains; - int cld; - int tid; - int rv; - int i; - - apr_pool_create(&pchild, pconf); - apr_pool_tag(pchild, "pchild"); - - ap_run_child_init(pchild, ap_server_conf); - ht = apr_hash_make(pchild); - - /* Initialize the child_events */ - max_requests_per_child_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!max_requests_per_child_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Failed to create a max_requests event.", my_pid); - exit(APEXIT_CHILDINIT); - } - child_events[0] = exit_event; - child_events[1] = max_requests_per_child_event; - - allowed_globals.jobsemaphore = CreateSemaphore(NULL, 0, 1000000, NULL); - apr_thread_mutex_create(&allowed_globals.jobmutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - - /* - * Wait until we have permission to start accepting connections. - * start_mutex is used to ensure that only one child ever - * goes into the listen/accept loop at once. - */ - status = apr_proc_mutex_lock(start_mutex); - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, status, ap_server_conf, - "Child %d: Failed to acquire the start_mutex. Process will exit.", my_pid); - exit(APEXIT_CHILDINIT); - } - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Acquired the start mutex.", my_pid); - - /* - * Create the worker thread dispatch IOCompletionPort - * on Windows NT/2000 - */ - if (use_acceptex) { - /* Create the worker thread dispatch IOCP */ - ThreadDispatchIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, - NULL, - 0, - 0); /* CONCURRENT ACTIVE THREADS */ - apr_thread_mutex_create(&qlock, APR_THREAD_MUTEX_DEFAULT, pchild); - qwait_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!qwait_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Failed to create a qwait event.", my_pid); - exit(APEXIT_CHILDINIT); - } - } - - /* - * Create the pool of worker threads - */ - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Starting %d worker threads.", my_pid, ap_threads_per_child); - child_handles = (HANDLE) apr_pcalloc(pchild, ap_threads_per_child * sizeof(int)); - apr_thread_mutex_create(&child_lock, APR_THREAD_MUTEX_DEFAULT, pchild); - - while (1) { - for (i = 0; i < ap_threads_per_child; i++) { - int *score_idx; - int status = ap_scoreboard_image->servers[0][i].status; - if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { - continue; - } - ap_update_child_status_from_indexes(0, i, SERVER_STARTING, NULL); - child_handles[i] = (HANDLE) _beginthreadex(NULL, 0, worker_main, - (void *) i, 0, &tid); - if (child_handles[i] == 0) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: _beginthreadex failed. Unable to create all worker threads. " - "Created %d of the %d threads requested with the ThreadsPerChild configuration directive.", - my_pid, threads_created, ap_threads_per_child); - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - goto shutdown; - } - threads_created++; - /* Save the score board index in ht keyed to the thread handle. We need this - * when cleaning up threads down below... - */ - apr_thread_mutex_lock(child_lock); - score_idx = apr_pcalloc(pchild, sizeof(int)); - *score_idx = i; - apr_hash_set(ht, &child_handles[i], sizeof(HANDLE), score_idx); - apr_thread_mutex_unlock(child_lock); - } - /* Start the listener only when workers are available */ - if (!listener_started && threads_created) { - create_listener_thread(); - listener_started = 1; - winnt_mpm_state = AP_MPMQ_RUNNING; - } - if (threads_created == ap_threads_per_child) { - break; - } - /* Check to see if the child has been told to exit */ - if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT) { - break; - } - /* wait for previous generation to clean up an entry in the scoreboard */ - apr_sleep(1 * APR_USEC_PER_SEC); - } - - /* Wait for one of three events: - * exit_event: - * The exit_event is signaled by the parent process to notify - * the child that it is time to exit. - * - * max_requests_per_child_event: - * This event is signaled by the worker threads to indicate that - * the process has handled MaxRequestsPerChild connections. - * - * TIMEOUT: - * To do periodic maintenance on the server (check for thread exits, - * number of completion contexts, etc.) - * - * XXX: thread exits *aren't* being checked. - * - * XXX: other_child - we need the process handles to the other children - * in order to map them to apr_proc_other_child_read (which is not - * named well, it's more like a_p_o_c_died.) - * - * XXX: however - if we get a_p_o_c handle inheritance working, and - * the parent process creates other children and passes the pipes - * to our worker processes, then we have no business doing such - * things in the child_main loop, but should happen in master_main. - */ - while (1) { -#if !APR_HAS_OTHER_CHILD - rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, INFINITE); - cld = rv - WAIT_OBJECT_0; -#else - rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, 1000); - cld = rv - WAIT_OBJECT_0; - if (rv == WAIT_TIMEOUT) { - apr_proc_other_child_check(); - } - else -#endif - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: WAIT_FAILED -- shutting down server", my_pid); - break; - } - else if (cld == 0) { - /* Exit event was signaled */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Exit event signaled. Child process is ending.", my_pid); - break; - } - else { - /* MaxRequestsPerChild event set by the worker threads. - * Signal the parent to restart - */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Process exiting because it reached " - "MaxRequestsPerChild. Signaling the parent to " - "restart a new child process.", my_pid); - ap_signal_parent(SIGNAL_PARENT_RESTART); - break; - } - } - - /* - * Time to shutdown the child process - */ - - shutdown: - - winnt_mpm_state = AP_MPMQ_STOPPING; - /* Setting is_graceful will cause threads handling keep-alive connections - * to close the connection after handling the current request. - */ - is_graceful = 1; - - /* Close the listening sockets. Note, we must close the listeners - * before closing any accept sockets pending in AcceptEx to prevent - * memory leaks in the kernel. - */ - for (lr = ap_listeners; lr ; lr = lr->next) { - apr_socket_close(lr->sd); - } - - /* Shutdown listener threads and pending AcceptEx socksts - * but allow the worker threads to continue consuming from - * the queue of accepted connections. - */ - shutdown_in_progress = 1; - - Sleep(1000); - - /* Tell the worker threads to exit */ - workers_may_exit = 1; - - /* Release the start_mutex to let the new process (in the restart - * scenario) a chance to begin accepting and servicing requests - */ - rv = apr_proc_mutex_unlock(start_mutex); - if (rv == APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_NOTICE, rv, ap_server_conf, - "Child %d: Released the start mutex", my_pid); - } - else { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "Child %d: Failure releasing the start mutex", my_pid); - } - - /* Shutdown the worker threads */ - if (!use_acceptex) { - for (i = 0; i < threads_created; i++) { - add_job(INVALID_SOCKET); - } - } - else { /* Windows NT/2000 */ - /* Post worker threads blocked on the ThreadDispatch IOCompletion port */ - while (g_blocked_threads > 0) { - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Child %d: %d threads blocked on the completion port", my_pid, g_blocked_threads); - for (i=g_blocked_threads; i > 0; i--) { - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_SHUTDOWN, NULL); - } - Sleep(1000); - } - /* Empty the accept queue of completion contexts */ - apr_thread_mutex_lock(qlock); - while (qhead) { - CloseHandle(qhead->Overlapped.hEvent); - closesocket(qhead->accept_socket); - qhead = qhead->next; - } - apr_thread_mutex_unlock(qlock); - } - - /* Give busy threads a chance to service their connections, - * (no more than the global server timeout period which - * we track in msec remaining). - */ - watch_thread = 0; - time_remains = (int)(ap_server_conf->timeout / APR_TIME_C(1000)); - - while (threads_created) - { - int nFailsafe = MAXIMUM_WAIT_OBJECTS; - DWORD dwRet; - - /* Every time we roll over to wait on the first group - * of MAXIMUM_WAIT_OBJECTS threads, take a breather, - * and infrequently update the error log. - */ - if (watch_thread >= threads_created) { - if ((time_remains -= 100) < 0) - break; - - /* Every 30 seconds give an update */ - if ((time_remains % 30000) == 0) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, - ap_server_conf, - "Child %d: Waiting %d more seconds " - "for %d worker threads to finish.", - my_pid, time_remains / 1000, threads_created); - } - /* We'll poll from the top, 10 times per second */ - Sleep(100); - watch_thread = 0; - } - - /* Fairness, on each iteration we will pick up with the thread - * after the one we just removed, even if it's a single thread. - * We don't block here. - */ - dwRet = WaitForMultipleObjects(min(threads_created - watch_thread, - MAXIMUM_WAIT_OBJECTS), - child_handles + watch_thread, 0, 0); - - if (dwRet == WAIT_FAILED) { - break; - } - if (dwRet == WAIT_TIMEOUT) { - /* none ready */ - watch_thread += MAXIMUM_WAIT_OBJECTS; - continue; - } - else if (dwRet >= WAIT_ABANDONED_0) { - /* We just got the ownership of the object, which - * should happen at most MAXIMUM_WAIT_OBJECTS times. - * It does NOT mean that the object is signaled. - */ - if ((nFailsafe--) < 1) - break; - } - else { - watch_thread += (dwRet - WAIT_OBJECT_0); - if (watch_thread >= threads_created) - break; - cleanup_thread(child_handles, &threads_created, watch_thread); - } - } - - /* Kill remaining threads off the hard way */ - if (threads_created) { - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Terminating %d threads that failed to exit.", - my_pid, threads_created); - } - for (i = 0; i < threads_created; i++) { - int *score_idx; - TerminateThread(child_handles[i], 1); - CloseHandle(child_handles[i]); - /* Reset the scoreboard entry for the thread we just whacked */ - score_idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE)); - ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL); - } - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: All worker threads have exited.", my_pid); - - CloseHandle(allowed_globals.jobsemaphore); - apr_thread_mutex_destroy(allowed_globals.jobmutex); - apr_thread_mutex_destroy(child_lock); - - if (use_acceptex) { - apr_thread_mutex_destroy(qlock); - CloseHandle(qwait_event); - } - - apr_pool_destroy(pchild); - CloseHandle(exit_event); -} - -#endif /* def WIN32 */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h deleted file mode 100644 index 2cae7a8e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_H -#define APACHE_MPM_H - -/* mpm.h is the place to make declarations that are MPM specific but that must be - * shared with non-mpm specific code in the server. Hummm, perhaps we can - * move most of this stuff to mpm_common.h? - */ - -#include "scoreboard.h" - -#define MPM_NAME "WinNT" - -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_MAX_MEM_FREE - -extern int ap_threads_per_child; -extern int ap_thread_limit; -extern server_rec *ap_server_conf; - -#endif /* APACHE_MPM_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h deleted file mode 100644 index 847bd732..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* Default limit on the maximum setting of the ThreadsPerChild configuration - * directive. This limit can be overridden with the ThreadLimit directive. - * This limit directly influences the amount of shared storage that is allocated - * for the scoreboard. DEFAULT_THREAD_LIMIT represents a good compromise - * between scoreboard size and the ability of the server to handle the most - * common installation requirements. - */ -#ifndef DEFAULT_THREAD_LIMIT -#define DEFAULT_THREAD_LIMIT 1920 -#endif - -/* The ThreadLimit directive can be used to override the DEFAULT_THREAD_LIMIT. - * ThreadLimit cannot be tuned larger than MAX_THREAD_LIMIT. - * This is a sort of compile-time limit to help catch typos. - */ -#ifndef MAX_THREAD_LIMIT -#define MAX_THREAD_LIMIT 15000 -#endif - -/* Number of threads started in the child process in the absence - * of a ThreadsPerChild configuration directive - */ -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 64 -#endif - -/* Max number of child processes allowed. - */ -#define HARD_SERVER_LIMIT 1 - -/* Number of servers to spawn off by default - */ -#ifndef DEFAULT_NUM_DAEMON -#define DEFAULT_NUM_DAEMON 1 -#endif - -/* Check for definition of DEFAULT_REL_RUNTIMEDIR */ -#ifndef DEFAULT_REL_RUNTIMEDIR -#define DEFAULT_REL_RUNTIMEDIR "logs" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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 0 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c deleted file mode 100644 index 6fc0ae60..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c +++ /dev/null @@ -1,1728 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef WIN32 - -#define CORE_PRIVATE -#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 "apr_portable.h" -#include "apr_thread_proc.h" -#include "apr_getopt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_shm.h" -#include "apr_thread_mutex.h" -#include "ap_mpm.h" -#include "ap_config.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm_winnt.h" -#include "mpm_common.h" -#include <malloc.h> -#include "apr_atomic.h" - - -/* scoreboard.c does the heavy lifting; all we do is create the child - * score by moving a handle down the pipe into the child's stdin. - */ -extern apr_shm_t *ap_scoreboard_shm; -server_rec *ap_server_conf; - -/* Definitions of WINNT MPM specific config globals */ -static HANDLE shutdown_event; /* used to signal the parent to shutdown */ -static HANDLE restart_event; /* used to signal the parent to restart */ - -static char ap_coredump_dir[MAX_STRING_LEN]; - -static int one_process = 0; -static char const* signal_arg = NULL; - -OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */ - -static DWORD parent_pid; -DWORD my_pid; - -int ap_threads_per_child = 0; -int use_acceptex = 1; -static int thread_limit = DEFAULT_THREAD_LIMIT; -static int first_thread_limit = 0; -static int changed_limit_at_restart; -int winnt_mpm_state = AP_MPMQ_STARTING; -/* ap_my_generation are used by the scoreboard code */ -ap_generation_t volatile ap_my_generation=0; - - -/* shared by service.c as global, although - * perhaps it should be private. - */ -apr_pool_t *pconf; - - -/* definitions from child.c */ -void child_main(apr_pool_t *pconf); - -/* used by parent to signal the child to start and exit - * NOTE: these are not sophisticated enough for multiple children - * so they ultimately should not be shared with child.c - */ -extern apr_proc_mutex_t *start_mutex; -extern HANDLE exit_event; - -/* Only one of these, the pipe from our parent, ment only for - * one child worker's consumption (not to be inherited!) - * XXX: decorate this name for the trunk branch, was left simplified - * only to make the 2.2 patch trivial to read. - */ -static HANDLE pipe; - -/* Stub functions until this MPM supports the connection status API */ - -AP_DECLARE(void) ap_update_connection_status(long conn_id, const char *key, \ - const char *value) -{ - /* NOP */ -} - -AP_DECLARE(void) ap_reset_connection_status(long conn_id) -{ - /* NOP */ -} - -AP_DECLARE(apr_array_header_t *) ap_get_status_table(apr_pool_t *p) -{ - /* NOP */ - return NULL; -} - -/* - * Command processors - */ - -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 > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d threads,", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_thread_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d threads,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } - return NULL; -} -static const char *set_disable_acceptex(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - if (use_acceptex) { - use_acceptex = 0; - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, - "Disabled use of AcceptEx() WinSock2 API"); - } - return NULL; -} - -static const command_rec winnt_cmds[] = { -LISTEN_COMMANDS, -AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates" ), -AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, - "Maximum worker threads in a server for this run of Apache"), -AP_INIT_NO_ARGS("Win32DisableAcceptEx", set_disable_acceptex, NULL, RSRC_CONF, - "Disable use of the high performance AcceptEx WinSock2 API to work around buggy VPN or Firewall software"), -{ NULL } -}; - - -/* - * Signalling Apache on NT. - * - * Under Unix, Apache can be told to shutdown or restart by sending various - * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so - * we use "events" instead. The parent apache process goes into a loop - * where it waits forever for a set of events. Two of those events are - * called - * - * apPID_shutdown - * apPID_restart - * - * (where PID is the PID of the apache parent process). When one of these - * is signalled, the Apache parent performs the appropriate action. The events - * can become signalled through internal Apache methods (e.g. if the child - * finds a fatal error and needs to kill its parent), via the service - * control manager (the control thread will signal the shutdown event when - * requested to stop the Apache service), from the -k Apache command line, - * or from any external program which finds the Apache PID from the - * httpd.pid file. - * - * The signal_parent() function, below, is used to signal one of these events. - * It can be called by any child or parent process, since it does not - * rely on global variables. - * - * On entry, type gives the event to signal. 0 means shutdown, 1 means - * graceful restart. - */ -/* - * Initialise the signal names, in the global variables signal_name_prefix, - * signal_restart_name and signal_shutdown_name. - */ -#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */ -char signal_name_prefix[MAX_SIGNAL_NAME]; -char signal_restart_name[MAX_SIGNAL_NAME]; -char signal_shutdown_name[MAX_SIGNAL_NAME]; -void setup_signal_names(char *prefix) -{ - apr_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix); - apr_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), - "%s_shutdown", signal_name_prefix); - apr_snprintf(signal_restart_name, sizeof(signal_restart_name), - "%s_restart", signal_name_prefix); -} - -int volatile is_graceful = 0; - -AP_DECLARE(int) ap_graceful_stop_signalled(void) -{ - return is_graceful; -} - -AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type) -{ - HANDLE e; - char *signal_name; - - if (parent_pid == my_pid) { - switch(type) { - case SIGNAL_PARENT_SHUTDOWN: - { - SetEvent(shutdown_event); - break; - } - /* This MPM supports only graceful restarts right now */ - case SIGNAL_PARENT_RESTART: - case SIGNAL_PARENT_RESTART_GRACEFUL: - { - is_graceful = 1; - SetEvent(restart_event); - break; - } - } - return; - } - - switch(type) { - case SIGNAL_PARENT_SHUTDOWN: - { - signal_name = signal_shutdown_name; - break; - } - /* This MPM supports only graceful restarts right now */ - case SIGNAL_PARENT_RESTART: - case SIGNAL_PARENT_RESTART_GRACEFUL: - { - signal_name = signal_restart_name; - is_graceful = 1; - break; - } - default: - return; - } - - e = OpenEvent(EVENT_MODIFY_STATE, FALSE, signal_name); - if (!e) { - /* Um, problem, can't signal the parent, which means we can't - * signal ourselves to die. Ignore for now... - */ - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf, - "OpenEvent on %s event", signal_name); - return; - } - if (SetEvent(e) == 0) { - /* Same problem as above */ - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf, - "SetEvent on %s event", signal_name); - CloseHandle(e); - return; - } - CloseHandle(e); -} - - -/* - * Passed the following handles [in sync with send_handles_to_child()] - * - * ready event [signal the parent immediately, then close] - * exit event [save to poll later] - * start mutex [signal from the parent to begin accept()] - * scoreboard shm handle [to recreate the ap_scoreboard] - */ -void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event, - apr_proc_mutex_t **child_start_mutex, - apr_shm_t **scoreboard_shm) -{ - HANDLE hScore; - HANDLE ready_event; - HANDLE os_start; - DWORD BytesRead; - void *sb_shared; - apr_status_t rv; - - /* *** We now do this was back in winnt_rewrite_args - * pipe = GetStdHandle(STD_INPUT_HANDLE); - */ - if (!ReadFile(pipe, &ready_event, sizeof(HANDLE), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(HANDLE))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the ready event from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - SetEvent(ready_event); - CloseHandle(ready_event); - - if (!ReadFile(pipe, child_exit_event, sizeof(HANDLE), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(HANDLE))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the exit event from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - if (!ReadFile(pipe, &os_start, sizeof(os_start), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(os_start))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the start_mutex from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - *child_start_mutex = NULL; - if ((rv = apr_os_proc_mutex_put(child_start_mutex, &os_start, s->process->pool)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Child %d: Unable to access the start_mutex from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - if (!ReadFile(pipe, &hScore, sizeof(hScore), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(hScore))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the scoreboard from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - *scoreboard_shm = NULL; - if ((rv = apr_os_shm_put(scoreboard_shm, &hScore, s->process->pool)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Child %d: Unable to access the scoreboard from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - rv = ap_reopen_scoreboard(s->process->pool, scoreboard_shm, 1); - if (rv || !(sb_shared = apr_shm_baseaddr_get(*scoreboard_shm))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "Child %d: Unable to reopen the scoreboard from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - /* We must 'initialize' the scoreboard to relink all the - * process-local pointer arrays into the shared memory block. - */ - ap_init_scoreboard(sb_shared); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Child %d: Retrieved our scoreboard from the parent.", my_pid); -} - - -static int send_handles_to_child(apr_pool_t *p, - HANDLE child_ready_event, - HANDLE child_exit_event, - apr_proc_mutex_t *child_start_mutex, - apr_shm_t *scoreboard_shm, - HANDLE hProcess, - apr_file_t *child_in) -{ - apr_status_t rv; - HANDLE hCurrentProcess = GetCurrentProcess(); - HANDLE hDup; - HANDLE os_start; - HANDLE hScore; - DWORD BytesWritten; - - if (!DuplicateHandle(hCurrentProcess, child_ready_event, hProcess, &hDup, - EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the ready event handle for the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the exit event handle to the child"); - return -1; - } - if (!DuplicateHandle(hCurrentProcess, child_exit_event, hProcess, &hDup, - EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the exit event handle for the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the exit event handle to the child"); - return -1; - } - if ((rv = apr_os_proc_mutex_get(&os_start, child_start_mutex)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to retrieve the start mutex for the child"); - return -1; - } - if (!DuplicateHandle(hCurrentProcess, os_start, hProcess, &hDup, - SYNCHRONIZE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the start mutex to the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the start mutex to the child"); - return -1; - } - if ((rv = apr_os_shm_get(&hScore, scoreboard_shm)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to retrieve the scoreboard handle for the child"); - return -1; - } - if (!DuplicateHandle(hCurrentProcess, hScore, hProcess, &hDup, - FILE_MAP_READ | FILE_MAP_WRITE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the scoreboard handle to the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the scoreboard handle to the child"); - return -1; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Parent: Sent the scoreboard to the child"); - return 0; -} - - -/* - * get_listeners_from_parent() - * The listen sockets are opened in the parent. This function, which runs - * exclusively in the child process, receives them from the parent and - * makes them availeble in the child. - */ -void get_listeners_from_parent(server_rec *s) -{ - WSAPROTOCOL_INFO WSAProtocolInfo; - ap_listen_rec *lr; - DWORD BytesRead; - int lcnt = 0; - SOCKET nsd; - - /* Set up a default listener if necessary */ - if (ap_listeners == NULL) { - ap_listen_rec *lr; - lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec)); - lr->sd = NULL; - lr->next = ap_listeners; - ap_listeners = lr; - } - - /* Open the pipe to the parent process to receive the inherited socket - * data. The sockets have been set to listening in the parent process. - * - * *** We now do this was back in winnt_rewrite_args - * pipe = GetStdHandle(STD_INPUT_HANDLE); - */ - for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { - if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), - &BytesRead, (LPOVERLAPPED) NULL)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "setup_inherited_listeners: Unable to read socket data from parent"); - exit(APEXIT_CHILDINIT); - } - nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - &WSAProtocolInfo, 0, 0); - if (nsd == INVALID_SOCKET) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf, - "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid); - exit(APEXIT_CHILDINIT); - } - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - HANDLE hProcess = GetCurrentProcess(); - HANDLE dup; - if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - closesocket(nsd); - nsd = (SOCKET) dup; - } - } - else { - /* A different approach. Many users report errors such as - * (32538)An operation was attempted on something that is not - * a socket. : Parent: WSADuplicateSocket failed... - * - * This appears that the duplicated handle is no longer recognized - * as a socket handle. SetHandleInformation should overcome that - * problem by not altering the handle identifier. But this won't - * work on 9x - it's unsupported. - */ - if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf, - "set_listeners_noninheritable: SetHandleInformation failed."); - } - } - apr_os_sock_put(&lr->sd, &nsd, s->process->pool); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Child %d: retrieved %d listeners from parent", my_pid, lcnt); -} - - -static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId, - apr_file_t *child_in) -{ - apr_status_t rv; - int lcnt = 0; - ap_listen_rec *lr; - LPWSAPROTOCOL_INFO lpWSAProtocolInfo; - DWORD BytesWritten; - - /* Run the chain of open sockets. For each socket, duplicate it - * for the target process then send the WSAPROTOCOL_INFO - * (returned by dup socket) to the child. - */ - for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { - int nsd; - lpWSAProtocolInfo = apr_pcalloc(p, sizeof(WSAPROTOCOL_INFO)); - apr_os_sock_get(&nsd,lr->sd); - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Parent: Duplicating socket %d and sending it to child process %d", - nsd, dwProcessId); - if (WSADuplicateSocket(nsd, dwProcessId, - lpWSAProtocolInfo) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf, - "Parent: WSADuplicateSocket failed for socket %d. Check the FAQ.", lr->sd ); - return -1; - } - - if ((rv = apr_file_write_full(child_in, lpWSAProtocolInfo, - sizeof(WSAPROTOCOL_INFO), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to write duplicated socket %d to the child.", lr->sd ); - return -1; - } - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Parent: Sent %d listeners to child %d", lcnt, dwProcessId); - return 0; -} - -enum waitlist_e { - waitlist_ready = 0, - waitlist_term = 1 -}; - -static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_event, - DWORD *child_pid) -{ - /* These NEVER change for the lifetime of this parent - */ - static char **args = NULL; - static char pidbuf[28]; - - apr_status_t rv; - apr_pool_t *ptemp; - apr_procattr_t *attr; - apr_proc_t new_child; - apr_file_t *child_out, *child_err; - HANDLE hExitEvent; - HANDLE waitlist[2]; /* see waitlist_e */ - char *cmd; - char *cwd; - char **env; - int envc; - - apr_pool_sub_make(&ptemp, p, NULL); - - /* Build the command line. Should look something like this: - * C:/apache/bin/apache.exe -f ap_server_confname - * First, get the path to the executable... - */ - apr_procattr_create(&attr, ptemp); - apr_procattr_cmdtype_set(attr, APR_PROGRAM); - apr_procattr_detach_set(attr, 1); - if (((rv = apr_filepath_get(&cwd, 0, ptemp)) != APR_SUCCESS) - || ((rv = apr_procattr_dir_set(attr, cwd)) != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Failed to get the current path"); - } - - if (!args) { - /* Build the args array, only once since it won't change - * for the lifetime of this parent process. - */ - if ((rv = ap_os_proc_filepath(&cmd, ptemp)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, ERROR_BAD_PATHNAME, ap_server_conf, - "Parent: Failed to get full path of %s", - ap_server_conf->process->argv[0]); - apr_pool_destroy(ptemp); - return -1; - } - - args = malloc((ap_server_conf->process->argc + 1) * sizeof (char*)); - memcpy(args + 1, ap_server_conf->process->argv + 1, - (ap_server_conf->process->argc - 1) * sizeof (char*)); - args[0] = malloc(strlen(cmd) + 1); - strcpy(args[0], cmd); - args[ap_server_conf->process->argc] = NULL; - } - else { - cmd = args[0]; - } - - /* Create a pipe to send handles to the child */ - if ((rv = apr_procattr_io_set(attr, APR_FULL_BLOCK, - APR_NO_PIPE, APR_NO_PIPE)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to create child stdin pipe."); - apr_pool_destroy(ptemp); - return -1; - } - - /* httpd-2.0/2.2 specific to work around apr_proc_create bugs */ - /* set "NUL" as sysout for the child */ - if (((rv = apr_file_open(&child_out, "NUL", APR_WRITE | APR_READ, APR_OS_DEFAULT,p)) - != APR_SUCCESS) || - ((rv = apr_procattr_child_out_set(attr, child_out, NULL)) - != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "Parent: Could not set child process stdout"); - } - if (((rv = apr_file_open_stderr(&child_err, p)) - != APR_SUCCESS) || - ((rv = apr_procattr_child_err_set(attr, child_err, NULL)) - != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "Parent: Could not set child process stderr"); - } - - /* Create the child_ready_event */ - waitlist[waitlist_ready] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!waitlist[waitlist_ready]) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Could not create ready event for child process"); - apr_pool_destroy (ptemp); - return -1; - } - - /* Create the child_exit_event */ - hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!hExitEvent) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Could not create exit event for child process"); - apr_pool_destroy(ptemp); - CloseHandle(waitlist[waitlist_ready]); - return -1; - } - - /* Build the env array */ - for (envc = 0; _environ[envc]; ++envc) { - ; - } - env = apr_palloc(ptemp, (envc + 2) * sizeof (char*)); - memcpy(env, _environ, envc * sizeof (char*)); - apr_snprintf(pidbuf, sizeof(pidbuf), "AP_PARENT_PID=%i", parent_pid); - env[envc] = pidbuf; - env[envc + 1] = NULL; - - rv = apr_proc_create(&new_child, cmd, args, env, attr, ptemp); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Failed to create the child process."); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(waitlist[waitlist_ready]); - CloseHandle(new_child.hproc); - return -1; - } - apr_file_close(child_out); - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: Created child process %d", new_child.pid); - - if (send_handles_to_child(ptemp, waitlist[waitlist_ready], hExitEvent, - start_mutex, ap_scoreboard_shm, - new_child.hproc, new_child.in)) { - /* - * This error is fatal, mop up the child and move on - * We toggle the child's exit event to cause this child - * to quit even as it is attempting to start. - */ - SetEvent(hExitEvent); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(waitlist[waitlist_ready]); - CloseHandle(new_child.hproc); - return -1; - } - - /* Important: - * Give the child process a chance to run before dup'ing the sockets. - * We have already set the listening sockets noninheritable, but if - * WSADuplicateSocket runs before the child process initializes - * the listeners will be inherited anyway. - */ - waitlist[waitlist_term] = new_child.hproc; - rv = WaitForMultipleObjects(2, waitlist, FALSE, INFINITE); - CloseHandle(waitlist[waitlist_ready]); - if (rv != WAIT_OBJECT_0) { - /* - * Outch... that isn't a ready signal. It's dead, Jim! - */ - SetEvent(hExitEvent); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(new_child.hproc); - return -1; - } - - if (send_listeners_to_child(ptemp, new_child.pid, new_child.in)) { - /* - * This error is fatal, mop up the child and move on - * We toggle the child's exit event to cause this child - * to quit even as it is attempting to start. - */ - SetEvent(hExitEvent); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(new_child.hproc); - return -1; - } - - apr_file_close(new_child.in); - - *child_exit_event = hExitEvent; - *child_proc = new_child.hproc; - *child_pid = new_child.pid; - - return 0; -} - -/*********************************************************************** - * master_main() - * master_main() runs in the parent process. It creates the child - * process which handles HTTP requests then waits on one of three - * events: - * - * restart_event - * ------------- - * The restart event causes master_main to start a new child process and - * tells the old child process to exit (by setting the child_exit_event). - * The restart event is set as a result of one of the following: - * 1. An apache -k restart command on the command line - * 2. A command received from Windows service manager which gets - * translated into an ap_signal_parent(SIGNAL_PARENT_RESTART) - * call by code in service.c. - * 3. The child process calling ap_signal_parent(SIGNAL_PARENT_RESTART) - * as a result of hitting MaxRequestsPerChild. - * - * shutdown_event - * -------------- - * The shutdown event causes master_main to tell the child process to - * exit and that the server is shutting down. The shutdown event is - * set as a result of one of the following: - * 1. An apache -k shutdown command on the command line - * 2. A command received from Windows service manager which gets - * translated into an ap_signal_parent(SIGNAL_PARENT_SHUTDOWN) - * call by code in service.c. - * - * child process handle - * -------------------- - * The child process handle will be signaled if the child process - * exits for any reason. In a normal running server, the signaling - * of this event means that the child process has exited prematurely - * due to a seg fault or other irrecoverable error. For server - * robustness, master_main will restart the child process under this - * condtion. - * - * master_main uses the child_exit_event to signal the child process - * to exit. - **********************************************************************/ -#define NUM_WAIT_HANDLES 3 -#define CHILD_HANDLE 0 -#define SHUTDOWN_HANDLE 1 -#define RESTART_HANDLE 2 -static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_event) -{ - int rv, cld; - int restart_pending; - int shutdown_pending; - HANDLE child_exit_event; - HANDLE event_handles[NUM_WAIT_HANDLES]; - DWORD child_pid; - - restart_pending = shutdown_pending = 0; - - event_handles[SHUTDOWN_HANDLE] = shutdown_event; - event_handles[RESTART_HANDLE] = restart_event; - - /* Create a single child process */ - rv = create_process(pconf, &event_handles[CHILD_HANDLE], - &child_exit_event, &child_pid); - if (rv < 0) - { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "master_main: create child process failed. Exiting."); - shutdown_pending = 1; - goto die_now; - } - if (!strcasecmp(signal_arg, "runservice")) { - mpm_service_started(); - } - - /* Update the scoreboard. Note that there is only a single active - * child at once. - */ - ap_scoreboard_image->parent[0].quiescing = 0; - ap_scoreboard_image->parent[0].pid = child_pid; - - /* Wait for shutdown or restart events or for child death */ - winnt_mpm_state = AP_MPMQ_RUNNING; - rv = WaitForMultipleObjects(NUM_WAIT_HANDLES, (HANDLE *) event_handles, FALSE, INFINITE); - cld = rv - WAIT_OBJECT_0; - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK,APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "master_main: WaitForMultipeObjects WAIT_FAILED -- doing server shutdown"); - shutdown_pending = 1; - } - else if (rv == WAIT_TIMEOUT) { - /* Hey, this cannot happen */ - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); - shutdown_pending = 1; - } - else if (cld == SHUTDOWN_HANDLE) { - /* shutdown_event signalled */ - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, s, - "Parent: Received shutdown signal -- Shutting down the server."); - if (ResetEvent(shutdown_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "ResetEvent(shutdown_event)"); - } - } - else if (cld == RESTART_HANDLE) { - /* Received a restart event. Prepare the restart_event to be reused - * then signal the child process to exit. - */ - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "Parent: Received restart signal -- Restarting the server."); - if (ResetEvent(restart_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "Parent: ResetEvent(restart_event) failed."); - } - if (SetEvent(child_exit_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "Parent: SetEvent for child process %d failed.", - event_handles[CHILD_HANDLE]); - } - /* Don't wait to verify that the child process really exits, - * just move on with the restart. - */ - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - else { - /* The child process exited prematurely due to a fatal error. */ - DWORD exitcode; - if (!GetExitCodeProcess(event_handles[CHILD_HANDLE], &exitcode)) { - /* HUH? We did exit, didn't we? */ - exitcode = APEXIT_CHILDFATAL; - } - if ( exitcode == APEXIT_CHILDFATAL - || exitcode == APEXIT_CHILDINIT - || exitcode == APEXIT_INIT) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "Parent: child process exited with status %u -- Aborting.", exitcode); - } - else { - int i; - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: child process exited with status %u -- Restarting.", exitcode); - for (i = 0; i < ap_threads_per_child; i++) { - ap_update_child_status_from_indexes(0, i, SERVER_DEAD, NULL); - } - } - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - if (restart_pending) { - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - } -die_now: - if (shutdown_pending) - { - int timeout = 30000; /* Timeout is milliseconds */ - winnt_mpm_state = AP_MPMQ_STOPPING; - - /* This shutdown is only marginally graceful. We will give the - * child a bit of time to exit gracefully. If the time expires, - * the child will be wacked. - */ - if (!strcasecmp(signal_arg, "runservice")) { - mpm_service_stopping(); - } - /* Signal the child processes to exit */ - if (SetEvent(child_exit_event) == 0) { - ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), ap_server_conf, - "Parent: SetEvent for child process %d failed", event_handles[CHILD_HANDLE]); - } - if (event_handles[CHILD_HANDLE]) { - rv = WaitForSingleObject(event_handles[CHILD_HANDLE], timeout); - if (rv == WAIT_OBJECT_0) { - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: Child process exited successfully."); - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - else { - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: Forcing termination of child process %d ", event_handles[CHILD_HANDLE]); - TerminateProcess(event_handles[CHILD_HANDLE], 1); - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - } - CloseHandle(child_exit_event); - return 0; /* Tell the caller we do not want to restart */ - } - winnt_mpm_state = AP_MPMQ_STARTING; - CloseHandle(child_exit_event); - return 1; /* Tell the caller we want a restart */ -} - -/* service_nt_main_fn needs to append the StartService() args - * outside of our call stack and thread as the service starts... - */ -apr_array_header_t *mpm_new_argv; - -/* Remember service_to_start failures to log and fail in pre_config. - * Remember inst_argc and inst_argv for installing or starting the - * service after we preflight the config. - */ - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = MAXIMUM_WAIT_OBJECTS; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = thread_limit; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = winnt_mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -#define SERVICE_UNSET (-1) -static apr_status_t service_set = SERVICE_UNSET; -static apr_status_t service_to_start_success; -static int inst_argc; -static const char * const *inst_argv; -static char *service_name = NULL; - -void winnt_rewrite_args(process_rec *process) -{ - /* Handle the following SCM aspects in this phase: - * - * -k runservice [transition for WinNT, nothing for Win9x] - * -k (!)install [error out if name is not installed] - * -k uninstall - * -k stop - * -k shutdown (same as -k stop). Maintained for backward compatability. - * - * We can't leave this phase until we know our identity - * and modify the command arguments appropriately. - * - * We do not care if the .conf file exists or is parsable when - * attempting to stop or uninstall a service. - */ - apr_status_t rv; - char *def_server_root; - char *binpath; - char optbuf[3]; - const char *optarg; - int fixed_args; - char *pid; - apr_getopt_t *opt; - int running_as_service = 1; - int errout = 0; - - pconf = process->pconf; - - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osver); - - /* AP_PARENT_PID is only valid in the child */ - pid = getenv("AP_PARENT_PID"); - if (pid) - { - HANDLE filehand; - HANDLE hproc = GetCurrentProcess(); - - /* This is the child */ - my_pid = GetCurrentProcessId(); - parent_pid = (DWORD) atol(pid); - - /* Prevent holding open the (nonexistant) console */ - real_exit_code = 0; - - /* The parent gave us stdin, we need to remember this - * handle, and no longer inherit it at our children - * (we can't slurp it up now, we just aren't ready yet). - * The original handle is closed below, at apr_file_dup2() - */ - pipe = GetStdHandle(STD_INPUT_HANDLE); - if (DuplicateHandle(hproc, pipe, - hproc, &filehand, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - pipe = filehand; - } - - /* The parent gave us stdout of the NUL device, - * and expects us to suck up stdin of all of our - * shared handles and data from the parent. - * Don't infect child processes with our stdin - * handle, use another handle to NUL! - */ - { - apr_file_t *infile, *outfile; - if ((apr_file_open_stdout(&outfile, process->pool) == APR_SUCCESS) - && (apr_file_open_stdin(&infile, process->pool) == APR_SUCCESS)) - apr_file_dup2(infile, outfile, process->pool); - } - - /* This child needs the existing stderr opened for logging, - * already - */ - - /* The parent is responsible for providing the - * COMPLETE ARGUMENTS REQUIRED to the child. - * - * No further argument parsing is needed, but - * for good measure we will provide a simple - * signal string for later testing. - */ - signal_arg = "runchild"; - return; - } - - /* This is the parent, we have a long way to go :-) */ - parent_pid = my_pid = GetCurrentProcessId(); - - /* This behavior is voided by setting real_exit_code to 0 */ - atexit(hold_console_open_on_error); - - /* Rewrite process->argv[]; - * - * strip out -k signal into signal_arg - * strip out -n servicename and set the names - * add default -d serverroot from the path of this executable - * - * The end result will look like: - * - * The invocation command (%0) - * The -d serverroot default from the running executable - * The requested service's (-n) registry ConfigArgs - * The WinNT SCM's StartService() args - */ - if ((rv = ap_os_proc_filepath(&binpath, process->pconf)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_CRIT, rv, NULL, - "Failed to get the full path of %s", process->argv[0]); - exit(APEXIT_INIT); - } - /* WARNING: There is an implict assumption here that the - * executable resides in ServerRoot or ServerRoot\bin - */ - def_server_root = (char *) apr_filename_of_pathname(binpath); - if (def_server_root > binpath) { - *(def_server_root - 1) = '\0'; - def_server_root = (char *) apr_filename_of_pathname(binpath); - if (!strcasecmp(def_server_root, "bin")) - *(def_server_root - 1) = '\0'; - } - apr_filepath_merge(&def_server_root, NULL, binpath, - APR_FILEPATH_TRUENAME, process->pool); - - /* Use process->pool so that the rewritten argv - * lasts for the lifetime of the server process, - * because pconf will be destroyed after the - * initial pre-flight of the config parser. - */ - mpm_new_argv = apr_array_make(process->pool, process->argc + 2, - sizeof(const char *)); - *(const char **)apr_array_push(mpm_new_argv) = process->argv[0]; - *(const char **)apr_array_push(mpm_new_argv) = "-d"; - *(const char **)apr_array_push(mpm_new_argv) = def_server_root; - - fixed_args = mpm_new_argv->nelts; - - optbuf[0] = '-'; - optbuf[2] = '\0'; - apr_getopt_init(&opt, process->pool, process->argc, (char**) process->argv); - opt->errfn = NULL; - while ((rv = apr_getopt(opt, "wn:k:" AP_SERVER_BASEARGS, - optbuf + 1, &optarg)) == APR_SUCCESS) { - switch (optbuf[1]) { - - /* Shortcuts; include the -w option to hold the window open on error. - * This must not be toggled once we reset real_exit_code to 0! - */ - case 'w': - if (real_exit_code) - real_exit_code = 2; - break; - - case 'n': - service_set = mpm_service_set_name(process->pool, &service_name, - optarg); - break; - - case 'k': - signal_arg = optarg; - break; - - case 'E': - errout = 1; - /* Fall through so the Apache main() handles the 'E' arg */ - default: - *(const char **)apr_array_push(mpm_new_argv) = - apr_pstrdup(process->pool, optbuf); - - if (optarg) { - *(const char **)apr_array_push(mpm_new_argv) = optarg; - } - break; - } - } - - /* back up to capture the bad argument */ - if (rv == APR_BADCH || rv == APR_BADARG) { - opt->ind--; - } - - while (opt->ind < opt->argc) { - *(const char **)apr_array_push(mpm_new_argv) = - apr_pstrdup(process->pool, opt->argv[opt->ind++]); - } - - /* Track the number of args actually entered by the user */ - inst_argc = mpm_new_argv->nelts - fixed_args; - - /* Provide a default 'run' -k arg to simplify signal_arg tests */ - if (!signal_arg) - { - signal_arg = "run"; - running_as_service = 0; - } - - if (!strcasecmp(signal_arg, "runservice")) - { - /* Start the NT Service _NOW_ because the WinNT SCM is - * expecting us to rapidly assume control of our own - * process, the SCM will tell us our service name, and - * may have extra StartService() command arguments to - * add for us. - * - * The SCM will generally invoke the executable with - * the c:\win\system32 default directory. This is very - * lethal if folks use ServerRoot /foopath on windows - * without a drive letter. Change to the default root - * (path to apache root, above /bin) for safety. - */ - apr_filepath_set(def_server_root, process->pool); - - /* Any other process has a console, so we don't to begin - * a Win9x service until the configuration is parsed and - * any command line errors are reported. - * - * We hold the return value so that we can die in pre_config - * after logging begins, and the failure can land in the log. - */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - apr_file_t *nullfile; - - if (!errout) { - mpm_nt_eventlog_stderr_open(service_name, process->pool); - } - service_to_start_success = mpm_service_to_start(&service_name, - process->pool); - if (service_to_start_success == APR_SUCCESS) { - service_set = APR_SUCCESS; - } - - /* Open a null handle to soak stdout in this process. - * Windows service processes are missing any file handle - * usable for stdin/out/err. This was the cause of later - * trouble with invocations of apr_file_open_stdout() - */ - if ((rv = apr_file_open(&nullfile, "NUL", - APR_READ | APR_WRITE, APR_OS_DEFAULT, - process->pool)) == APR_SUCCESS) { - apr_file_t *nullstdout; - if (apr_file_open_stdout(&nullstdout, process->pool) - == APR_SUCCESS) - apr_file_dup2(nullstdout, nullfile, process->pool); - apr_file_close(nullfile); - } - } - } - - /* Get the default for any -k option, except run */ - if (service_set == SERVICE_UNSET && strcasecmp(signal_arg, "run")) { - service_set = mpm_service_set_name(process->pool, &service_name, - AP_DEFAULT_SERVICE_NAME); - } - - if (!strcasecmp(signal_arg, "install")) /* -k install */ - { - if (service_set == APR_SUCCESS) - { - ap_log_error(APLOG_MARK,APLOG_ERR, 0, NULL, - "%s: Service is already installed.", service_name); - exit(APEXIT_INIT); - } - } - else if (running_as_service) - { - if (service_set == APR_SUCCESS) - { - /* Attempt to Uninstall, or stop, before - * we can read the arguments or .conf files - */ - if (!strcasecmp(signal_arg, "uninstall")) { - rv = mpm_service_uninstall(); - exit(rv); - } - - if ((!strcasecmp(signal_arg, "stop")) || - (!strcasecmp(signal_arg, "shutdown"))) { - mpm_signal_service(process->pool, 0); - exit(0); - } - - rv = mpm_merge_service_args(process->pool, mpm_new_argv, - fixed_args); - if (rv == APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_INFO, 0, NULL, - "Using ConfigArgs of the installed service " - "\"%s\".", service_name); - } - else { - ap_log_error(APLOG_MARK,APLOG_WARNING, rv, NULL, - "No installed ConfigArgs for the service " - "\"%s\", using Apache defaults.", service_name); - } - } - else - { - ap_log_error(APLOG_MARK,APLOG_ERR, service_set, NULL, - "No installed service named \"%s\".", service_name); - exit(APEXIT_INIT); - } - } - if (strcasecmp(signal_arg, "install") && service_set && service_set != SERVICE_UNSET) - { - ap_log_error(APLOG_MARK,APLOG_ERR, service_set, NULL, - "No installed service named \"%s\".", service_name); - exit(APEXIT_INIT); - } - - /* Track the args actually entered by the user. - * These will be used for the -k install parameters, as well as - * for the -k start service override arguments. - */ - inst_argv = (const char * const *)mpm_new_argv->elts - + mpm_new_argv->nelts - inst_argc; - - process->argc = mpm_new_argv->nelts; - process->argv = (const char * const *) mpm_new_argv->elts; -} - - -static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *ptemp) -{ - /* Handle the following SCM aspects in this phase: - * - * -k runservice [WinNT errors logged from rewrite_args] - */ - - /* Initialize shared static objects. - */ - pconf = pconf_; - - if (ap_exists_config_define("ONE_PROCESS") || - ap_exists_config_define("DEBUG")) - one_process = -1; - - if (!strcasecmp(signal_arg, "runservice") - && (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - && (service_to_start_success != APR_SUCCESS)) { - ap_log_error(APLOG_MARK,APLOG_CRIT, service_to_start_success, NULL, - "%s: Unable to start the service manager.", - service_name); - exit(APEXIT_INIT); - } - - /* Win9x: disable AcceptEx */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - use_acceptex = 0; - } - - ap_listen_pre_config(); - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec* s) -{ - static int restart_num = 0; - apr_status_t rv = 0; - - /* Handle the following SCM aspects in this phase: - * - * -k install - * -k config - * -k start - * -k restart - * -k runservice [Win95, only once - after we parsed the config] - * - * because all of these signals are useful _only_ if there - * is a valid conf\httpd.conf environment to start. - * - * We reached this phase by avoiding errors that would cause - * these options to fail unexpectedly in another process. - */ - - if (!strcasecmp(signal_arg, "install")) { - rv = mpm_service_install(ptemp, inst_argc, inst_argv, 0); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - if (!strcasecmp(signal_arg, "config")) { - rv = mpm_service_install(ptemp, inst_argc, inst_argv, 1); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - - if (!strcasecmp(signal_arg, "start")) { - ap_listen_rec *lr; - - /* Close the listening sockets. */ - for (lr = ap_listeners; lr; lr = lr->next) { - apr_socket_close(lr->sd); - lr->active = 0; - } - rv = mpm_service_start(ptemp, inst_argc, inst_argv); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - - if (!strcasecmp(signal_arg, "restart")) { - mpm_signal_service(ptemp, 1); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - - if (parent_pid == my_pid) - { - if (restart_num++ == 1) - { - /* This code should be run once in the parent and not run - * across a restart - */ - PSECURITY_ATTRIBUTES sa = GetNullACL(); /* returns NULL if invalid (Win95?) */ - setup_signal_names(apr_psprintf(pconf,"ap%d", parent_pid)); - - ap_log_pid(pconf, ap_pid_fname); - - /* Create shutdown event, apPID_shutdown, where PID is the parent - * Apache process ID. Shutdown is signaled by 'apache -k shutdown'. - */ - shutdown_event = CreateEvent(sa, FALSE, FALSE, signal_shutdown_name); - if (!shutdown_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Cannot create shutdown event %s", signal_shutdown_name); - CleanNullACL((void *)sa); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Create restart event, apPID_restart, where PID is the parent - * Apache process ID. Restart is signaled by 'apache -k restart'. - */ - restart_event = CreateEvent(sa, FALSE, FALSE, signal_restart_name); - if (!restart_event) { - CloseHandle(shutdown_event); - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Cannot create restart event %s", signal_restart_name); - CleanNullACL((void *)sa); - return HTTP_INTERNAL_SERVER_ERROR; - } - CleanNullACL((void *)sa); - - /* Now that we are flying at 15000 feet... - * wipe out the Win95 service console, - * signal the SCM the WinNT service started, or - * if not a service, setup console handlers instead. - */ - if (!strcasecmp(signal_arg, "runservice")) - { - if (osver.dwPlatformId != VER_PLATFORM_WIN32_NT) - { - rv = mpm_service_to_start(&service_name, - s->process->pool); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "%s: Unable to start the service manager.", - service_name); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - } - - /* Create the start mutex, as an unnamed object for security. - * Ths start mutex is used during a restart to prevent more than - * one child process from entering the accept loop at once. - */ - rv = apr_proc_mutex_create(&start_mutex, NULL, - APR_LOCK_DEFAULT, - ap_server_conf->process->pool); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "%s: Unable to create the start_mutex.", - service_name); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - /* Always reset our console handler to be the first, even on a restart - * because some modules (e.g. mod_perl) might have set a console - * handler to terminate the process. - */ - if (strcasecmp(signal_arg, "runservice")) - mpm_start_console_handler(); - } - else /* parent_pid != my_pid */ - { - mpm_start_child_console_handler(); - } - return OK; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int winnt_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - /* Initialize shared static objects. - */ - ap_server_conf = s; - - if (parent_pid != my_pid) { - return OK; - } - - /* We cannot initialize our listeners if we are restarting - * (the parent process already has glomed on to them) - * nor should we do so for service reconfiguration - * (since the service may already be running.) - */ - if (!strcasecmp(signal_arg, "restart") - || !strcasecmp(signal_arg, "config")) { - return OK; - } - - if (ap_setup_listeners(s) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - - return OK; -} - -static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s) -{ - apr_status_t rv; - - setup_signal_names(apr_psprintf(pchild,"ap%d", parent_pid)); - - /* This is a child process, not in single process mode */ - if (!one_process) { - /* Set up events and the scoreboard */ - get_handles_from_parent(s, &exit_event, &start_mutex, - &ap_scoreboard_shm); - - /* Set up the listeners */ - get_listeners_from_parent(s); - - /* Done reading from the parent, close that channel */ - CloseHandle(pipe); - - ap_my_generation = ap_scoreboard_image->global->running_generation; - } - else { - /* Single process mode - this lock doesn't even need to exist */ - rv = apr_proc_mutex_create(&start_mutex, signal_name_prefix, - APR_LOCK_DEFAULT, s->process->pool); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "%s child %d: Unable to init the start_mutex.", - service_name, my_pid); - exit(APEXIT_CHILDINIT); - } - - /* Borrow the shutdown_even as our _child_ loop exit event */ - exit_event = shutdown_event; - } -} - - -AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) -{ - static int restart = 0; /* Default is "not a restart" */ - - if (!restart) { - first_thread_limit = thread_limit; - } - - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ap_server_conf, - "WARNING: Attempt to change ThreadLimit ignored " - "during restart"); - changed_limit_at_restart = 0; - } - - /* ### If non-graceful restarts are ever introduced - we need to rerun - * the pre_mpm hook on subsequent non-graceful restarts. But Win32 - * has only graceful style restarts - and we need this hook to act - * the same on Win32 as on Unix. - */ - if (!restart && ((parent_pid == my_pid) || one_process)) { - /* Set up the scoreboard. */ - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - return 1; - } - } - - if ((parent_pid != my_pid) || one_process) - { - /* The child process or in one_process (debug) mode - */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Child process is running", my_pid); - - child_main(pconf); - - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Child process is exiting", my_pid); - return 1; - } - else - { - /* A real-honest to goodness parent */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - - restart = master_main(ap_server_conf, shutdown_event, restart_event); - - if (!restart) - { - /* Shutting down. Clean up... */ - const char *pidfile = ap_server_root_relative (pconf, ap_pid_fname); - - if (pidfile != NULL && unlink(pidfile) == 0) { - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, - ap_server_conf, "removed PID file %s (pid=%ld)", - pidfile, GetCurrentProcessId()); - } - apr_proc_mutex_destroy(start_mutex); - - CloseHandle(restart_event); - CloseHandle(shutdown_event); - - return 1; - } - } - - return 0; /* Restart */ -} - -static void winnt_hooks(apr_pool_t *p) -{ - /* The prefork open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - - ap_hook_pre_config(winnt_pre_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(winnt_post_config, NULL, NULL, 0); - ap_hook_child_init(winnt_child_init, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_open_logs(winnt_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); -} - -AP_MODULE_DECLARE_DATA module mpm_winnt_module = { - MPM20_MODULE_STUFF, - winnt_rewrite_args, /* 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 */ - winnt_cmds, /* command apr_table_t */ - winnt_hooks /* register_hooks */ -}; - -#endif /* def WIN32 */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h deleted file mode 100644 index 8eb04303..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_WINNT_H -#define APACHE_MPM_WINNT_H - -#include "ap_listen.h" - -/* From service.c: */ - -#define SERVICE_APACHE_RESTART 128 - -#ifndef AP_DEFAULT_SERVICE_NAME -#define AP_DEFAULT_SERVICE_NAME "Apache2" -#endif - -#define SERVICECONFIG9X "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices" -#define SERVICECONFIG "System\\CurrentControlSet\\Services\\%s" -#define SERVICEPARAMS "System\\CurrentControlSet\\Services\\%s\\Parameters" - -apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, - const char *set_name); -apr_status_t mpm_merge_service_args(apr_pool_t *p, apr_array_header_t *args, - int fixed_args); - -apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p); -apr_status_t mpm_service_started(void); -apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, - char const* const* argv, int reconfig); -apr_status_t mpm_service_uninstall(void); - -apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, - char const* const* argv); - -void mpm_signal_service(apr_pool_t *ptemp, int signal); - -void mpm_service_stopping(void); - -void mpm_start_console_handler(void); -void mpm_start_child_console_handler(void); - -/* From nt_eventlog.c: */ - -void mpm_nt_eventlog_stderr_open(char *display_name, apr_pool_t *p); -void mpm_nt_eventlog_stderr_flush(void); - -/* From winnt.c: */ -extern int use_acceptex; -extern int winnt_mpm_state; -extern OSVERSIONINFO osver; -extern void clean_child_exit(int); - -void setup_signal_names(char *prefix); - -typedef enum { - SIGNAL_PARENT_SHUTDOWN, - SIGNAL_PARENT_RESTART, - SIGNAL_PARENT_RESTART_GRACEFUL -} ap_signal_parent_e; -AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type); - -/* - * The Windoes MPM uses a queue of completion contexts that it passes - * between the accept threads and the worker threads. Declare the - * functions to access the queue and the structures passed on the - * queue in the header file to enable modules to access them - * if necessary. The queue resides in the MPM. - */ -#ifdef CONTAINING_RECORD -#undef CONTAINING_RECORD -#endif -#define CONTAINING_RECORD(address, type, field) ((type *)( \ - (PCHAR)(address) - \ - (PCHAR)(&((type *)0)->field))) -#define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16 -typedef struct CompContext { - struct CompContext *next; - OVERLAPPED Overlapped; - apr_socket_t *sock; - SOCKET accept_socket; - char buff[2*PADDED_ADDR_SIZE]; - struct sockaddr *sa_server; - int sa_server_len; - struct sockaddr *sa_client; - int sa_client_len; - apr_pool_t *ptrans; - apr_bucket_alloc_t *ba; -} COMP_CONTEXT, *PCOMP_CONTEXT; - -typedef enum { - IOCP_CONNECTION_ACCEPTED = 1, - IOCP_WAIT_FOR_RECEIVE = 2, - IOCP_WAIT_FOR_TRANSMITFILE = 3, - IOCP_SHUTDOWN = 4 -} io_state_e; - -AP_DECLARE(PCOMP_CONTEXT) mpm_get_completion_context(void); -AP_DECLARE(void) mpm_recycle_completion_context(PCOMP_CONTEXT pCompContext); -AP_DECLARE(apr_status_t) mpm_post_completion_context(PCOMP_CONTEXT pCompContext, io_state_e state); -void hold_console_open_on_error(void); -#endif /* APACHE_MPM_WINNT_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c deleted file mode 100644 index 37a349e8..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c +++ /dev/null @@ -1,175 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define CORE_PRIVATE - -#include "httpd.h" -#include "http_log.h" -#include "mpm_winnt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_portable.h" -#include "ap_regkey.h" - -static char *display_name = NULL; -static HANDLE stderr_thread = NULL; -static HANDLE stderr_ready; - -static DWORD WINAPI service_stderr_thread(LPVOID hPipe) -{ - HANDLE hPipeRead = (HANDLE) hPipe; - HANDLE hEventSource; - char errbuf[256]; - char *errmsg = errbuf; - const char *errarg[9]; - DWORD errres; - ap_regkey_t *regkey; - apr_status_t rv; - apr_pool_t *p; - - apr_pool_sub_make(&p, NULL, NULL); - - errarg[0] = "The Apache service named"; - errarg[1] = display_name; - errarg[2] = "reported the following error:\r\n>>>"; - errarg[3] = errbuf; - errarg[4] = NULL; - errarg[5] = NULL; - errarg[6] = NULL; - errarg[7] = NULL; - errarg[8] = NULL; - - /* What are we going to do in here, bail on the user? not. */ - if ((rv = ap_regkey_open(®key, AP_REGKEY_LOCAL_MACHINE, - "SYSTEM\\CurrentControlSet\\Services\\" - "EventLog\\Application\\Apache Service", - APR_READ | APR_WRITE | APR_CREATE, p)) - == APR_SUCCESS) - { - DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | - EVENTLOG_INFORMATION_TYPE; - - /* The stock message file */ - ap_regkey_value_set(regkey, "EventMessageFile", - "%SystemRoot%\\System32\\netmsg.dll", - AP_REGKEY_EXPAND, p); - - ap_regkey_value_raw_set(regkey, "TypesSupported", &dwData, - sizeof(dwData), REG_DWORD, p); - ap_regkey_close(regkey); - } - - hEventSource = RegisterEventSourceW(NULL, L"Apache Service"); - - SetEvent(stderr_ready); - - while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) - { - if ((errmsg > errbuf) || !apr_isspace(*errmsg)) - { - ++errmsg; - if ((*(errmsg - 1) == '\n') - || (errmsg >= errbuf + sizeof(errbuf) - 1)) - { - while ((errmsg > errbuf) && apr_isspace(*(errmsg - 1))) { - --errmsg; - } - *errmsg = '\0'; - - /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9' - * The event code in netmsg.dll is 3299 - */ - ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, - 3299, NULL, 9, 0, errarg, NULL); - errmsg = errbuf; - } - } - } - - if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) { - apr_snprintf(errbuf, sizeof(errbuf), - "Win32 error %d reading stderr pipe stream\r\n", - GetLastError()); - - ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, - 3299, NULL, 9, 0, errarg, NULL); - } - - CloseHandle(hPipeRead); - DeregisterEventSource(hEventSource); - CloseHandle(stderr_thread); - stderr_thread = NULL; - apr_pool_destroy(p); - return 0; -} - - -void mpm_nt_eventlog_stderr_flush(void) -{ - HANDLE cleanup_thread = stderr_thread; - - if (cleanup_thread) { - HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE); - fclose(stderr); - CloseHandle(hErr); - WaitForSingleObject(cleanup_thread, 30000); - CloseHandle(cleanup_thread); - } -} - - -void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p) -{ - SECURITY_ATTRIBUTES sa; - HANDLE hProc = GetCurrentProcess(); - HANDLE hPipeRead = NULL; - HANDLE hPipeWrite = NULL; - HANDLE hDup = NULL; - DWORD threadid; - apr_file_t *eventlog_file; - apr_file_t *stderr_file; - - display_name = argv0; - - /* Create a pipe to send stderr messages to the system error log. - * - * _dup2() duplicates the write handle inheritable for us. - */ - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = FALSE; - CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0); - ap_assert(hPipeRead && hPipeWrite); - - stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL); - stderr_thread = CreateThread(NULL, 0, service_stderr_thread, - (LPVOID) hPipeRead, 0, &threadid); - ap_assert(stderr_ready && stderr_thread); - - WaitForSingleObject(stderr_ready, INFINITE); - - if ((apr_file_open_stderr(&stderr_file, p) - == APR_SUCCESS) - && (apr_os_file_put(&eventlog_file, &hPipeWrite, APR_WRITE, p) - == APR_SUCCESS)) - apr_file_dup2(stderr_file, eventlog_file, p); - - /* The code above _will_ corrupt the StdHandle... - * and we must do so anyways. We set this up only - * after we initialized the posix stderr API. - */ - ap_open_stderr_log(p); -} diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c deleted file mode 100644 index 8739dc08..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c +++ /dev/null @@ -1,1346 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This module ALONE requires the window message API from user.h - * and the default APR include of windows.h will omit it, so - * preload the API symbols now... - */ - -#define CORE_PRIVATE -#define _WINUSER_ - -#include "httpd.h" -#include "http_log.h" -#include "mpm_winnt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "ap_regkey.h" - -#ifdef NOUSER -#undef NOUSER -#endif -#undef _WINUSER_ -#include <winuser.h> - -static char *mpm_service_name = NULL; -static char *mpm_display_name = NULL; - -static struct -{ - HANDLE mpm_thread; /* primary thread handle of the apache server */ - HANDLE service_thread; /* thread service/monitor handle */ - DWORD service_thread_id;/* thread service/monitor ID */ - HANDLE service_init; /* controller thread init mutex */ - HANDLE service_term; /* NT service thread kill signal */ - SERVICE_STATUS ssStatus; - SERVICE_STATUS_HANDLE hServiceStatus; -} globdat; - -static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint); - - -#define PRODREGKEY "SOFTWARE\\" AP_SERVER_BASEVENDOR "\\" \ - AP_SERVER_BASEPRODUCT "\\" AP_SERVER_BASEREVISION - -/* - * Get the server root from the registry into 'dir' which is - * size bytes long. Returns 0 if the server root was found - * or if the serverroot key does not exist (in which case - * dir will contain an empty string), or -1 if there was - * an error getting the key. - */ -apr_status_t ap_registry_get_server_root(apr_pool_t *p, char **buf) -{ - apr_status_t rv; - ap_regkey_t *key; - - if ((rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, PRODREGKEY, - APR_READ, p)) == APR_SUCCESS) { - rv = ap_regkey_value_get(buf, key, "ServerRoot", p); - ap_regkey_close(key); - if (rv == APR_SUCCESS) - return rv; - } - - if ((rv = ap_regkey_open(&key, AP_REGKEY_CURRENT_USER, PRODREGKEY, - APR_READ, p)) == APR_SUCCESS) { - rv = ap_regkey_value_get(buf, key, "ServerRoot", p); - ap_regkey_close(key); - if (rv == APR_SUCCESS) - return rv; - } - - *buf = NULL; - return rv; -} - - -/* The service configuration's is stored under the following trees: - * - * HKLM\System\CurrentControlSet\Services\[service name] - * - * \DisplayName - * \ImagePath - * \Parameters\ConfigArgs - * - * For Win9x, the launch service command is stored under: - * - * HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices\[service name] - */ - - -/* exit() for Win32 is macro mapped (horrible, we agree) that allows us - * to catch the non-zero conditions and inform the console process that - * the application died, and hang on to the console a bit longer. - * - * The macro only maps for http_main.c and other sources that include - * the service.h header, so we best assume it's an error to exit from - * _any_ other module. - * - * If real_exit_code is reset to 0, it will not be set or trigger this - * behavior on exit. All service and child processes are expected to - * reset this flag to zero to avoid undesireable side effects. - */ -AP_DECLARE_DATA int real_exit_code = 1; - -void hold_console_open_on_error(void) -{ - HANDLE hConIn; - HANDLE hConErr; - DWORD result; - time_t start; - time_t remains; - char *msg = "Note the errors or messages above, " - "and press the <ESC> key to exit. "; - CONSOLE_SCREEN_BUFFER_INFO coninfo; - INPUT_RECORD in; - char count[16]; - - if (!real_exit_code) - return; - hConIn = GetStdHandle(STD_INPUT_HANDLE); - hConErr = GetStdHandle(STD_ERROR_HANDLE); - if ((hConIn == INVALID_HANDLE_VALUE) || (hConErr == INVALID_HANDLE_VALUE)) - return; - if (!WriteConsole(hConErr, msg, strlen(msg), &result, NULL) || !result) - return; - if (!GetConsoleScreenBufferInfo(hConErr, &coninfo)) - return; - if (!SetConsoleMode(hConIn, ENABLE_MOUSE_INPUT | 0x80)) - return; - - start = time(NULL); - do - { - while (PeekConsoleInput(hConIn, &in, 1, &result) && result) - { - if (!ReadConsoleInput(hConIn, &in, 1, &result) || !result) - return; - if ((in.EventType == KEY_EVENT) && in.Event.KeyEvent.bKeyDown - && (in.Event.KeyEvent.uChar.AsciiChar == 27)) - return; - if (in.EventType == MOUSE_EVENT - && (in.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)) - return; - } - remains = ((start + 30) - time(NULL)); - sprintf (count, "%d...", remains); - if (!SetConsoleCursorPosition(hConErr, coninfo.dwCursorPosition)) - return; - if (!WriteConsole(hConErr, count, strlen(count), &result, NULL) - || !result) - return; - } - while ((remains > 0) && WaitForSingleObject(hConIn, 1000) != WAIT_FAILED); -} - -static BOOL die_on_logoff = FALSE; - -static LRESULT CALLBACK monitor_service_9x_proc(HWND hWnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ -/* This is the WndProc procedure for our invisible window. - * When the user shuts down the system, this window is sent - * a signal WM_ENDSESSION. We clean up by signaling Apache - * to shut down, and idle until Apache's primary thread quits. - */ - if ((msg == WM_ENDSESSION) - && (die_on_logoff || (lParam != ENDSESSION_LOGOFF))) - { - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - if (wParam) - /* Don't leave this message until we are dead! */ - WaitForSingleObject(globdat.mpm_thread, 30000); - return 0; - } - return (DefWindowProc(hWnd, msg, wParam, lParam)); -} - -static DWORD WINAPI monitor_service_9x_thread(void *service_name) -{ - /* When running as a service under Windows 9x, there is no console - * window present, and no ConsoleCtrlHandler to call when the system - * is shutdown. If the WatchWindow thread is created with a NULL - * service_name argument, then the ...SystemMonitor window class is - * used to create the "Apache" window to watch for logoff and shutdown. - * If the service_name is provided, the ...ServiceMonitor window class - * is used to create the window named by the service_name argument, - * and the logoff message is ignored. - */ - WNDCLASS wc; - HWND hwndMain; - MSG msg; - - wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = monitor_service_9x_proc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - if (service_name) - wc.lpszClassName = "ApacheWin95ServiceMonitor"; - else - wc.lpszClassName = "ApacheWin95SystemMonitor"; - - die_on_logoff = service_name ? FALSE : TRUE; - - if (!RegisterClass(&wc)) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Could not register window class for WatchWindow"); - globdat.service_thread_id = 0; - return 0; - } - - /* Create an invisible window */ - hwndMain = CreateWindow(wc.lpszClassName, - service_name ? (char *) service_name : "Apache", - WS_OVERLAPPEDWINDOW & ~WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, NULL, NULL, NULL, NULL); - - if (!hwndMain) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Could not create WatchWindow"); - globdat.service_thread_id = 0; - return 0; - } - - /* If we succeed, eliminate the console window. - * Signal the parent we are all set up, and - * watch the message queue while the window lives. - */ - FreeConsole(); - SetEvent(globdat.service_init); - - while (GetMessage(&msg, NULL, 0, 0)) - { - if (msg.message == WM_CLOSE) - DestroyWindow(hwndMain); - else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - globdat.service_thread_id = 0; - return 0; -} - - -static BOOL CALLBACK console_control_handler(DWORD ctrl_type) -{ - switch (ctrl_type) - { - case CTRL_BREAK_EVENT: - fprintf(stderr, "Apache server restarting...\n"); - ap_signal_parent(SIGNAL_PARENT_RESTART); - return TRUE; - case CTRL_C_EVENT: - fprintf(stderr, "Apache server interrupted...\n"); - /* for Interrupt signals, shut down the server. - * Tell the system we have dealt with the signal - * without waiting for Apache to terminate. - */ - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - return TRUE; - - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - /* for Terminate signals, shut down the server. - * Wait for Apache to terminate, but respond - * after a reasonable time to tell the system - * that we did attempt to shut ourself down. - * THESE EVENTS WILL NOT OCCUR UNDER WIN9x! - */ - fprintf(stderr, "Apache server shutdown initiated...\n"); - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - Sleep(30000); - return TRUE; - } - - /* We should never get here, but this is (mostly) harmless */ - return FALSE; -} - - -static void stop_console_handler(void) -{ - SetConsoleCtrlHandler(console_control_handler, FALSE); -} - - -void mpm_start_console_handler(void) -{ - SetConsoleCtrlHandler(console_control_handler, TRUE); - atexit(stop_console_handler); -} - - -/* Special situation - children of services need to mind their - * P's & Q's and wait quietly, ignoring the mean OS signaling - * shutdown and other horrors, to kill them gracefully... - */ - -static BOOL CALLBACK child_control_handler(DWORD ctrl_type) -{ - switch (ctrl_type) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - /* for Interrupt signals, ignore them. - * The system will also signal the parent process, - * which will terminate Apache. - */ - return TRUE; - - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - /* for Shutdown signals, ignore them, but... . - * The system will also signal the parent process, - * which will terminate Apache, so we need to wait. - */ - Sleep(30000); - return TRUE; - } - - /* We should never get here, but this is (mostly) harmless */ - return FALSE; -} - - -static void stop_child_console_handler(void) -{ - SetConsoleCtrlHandler(child_control_handler, FALSE); -} - - -void mpm_start_child_console_handler(void) -{ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - FreeConsole(); - } - else - { - SetConsoleCtrlHandler(child_control_handler, TRUE); - atexit(stop_child_console_handler); - } -} - - -/********************************** - WinNT service control management - **********************************/ - -static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint) -{ - static int checkPoint = 1; - int rv = APR_SUCCESS; - - if (globdat.hServiceStatus) - { - if (currentState == SERVICE_RUNNING) { - globdat.ssStatus.dwWaitHint = 0; - globdat.ssStatus.dwCheckPoint = 0; - globdat.ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - } - else if (currentState == SERVICE_STOPPED) { - globdat.ssStatus.dwWaitHint = 0; - globdat.ssStatus.dwCheckPoint = 0; - if (!exitCode && globdat.ssStatus.dwCurrentState - != SERVICE_STOP_PENDING) { - /* An unexpected exit? Better to error! */ - exitCode = 1; - } - if (exitCode) { - globdat.ssStatus.dwWin32ExitCode =ERROR_SERVICE_SPECIFIC_ERROR; - globdat.ssStatus.dwServiceSpecificExitCode = exitCode; - } - } - else { - globdat.ssStatus.dwCheckPoint = ++checkPoint; - globdat.ssStatus.dwControlsAccepted = 0; - if(waitHint) - globdat.ssStatus.dwWaitHint = waitHint; - } - - globdat.ssStatus.dwCurrentState = currentState; - - rv = SetServiceStatus(globdat.hServiceStatus, &globdat.ssStatus); - } - return(rv); -} - -/* Set the service description regardless of platform. - * We revert to set_service_description on NT/9x, the - * very long way so any Apache management program can grab the - * description. This would be bad on Win2000, since it wouldn't - * notify the service control manager of the name change. - */ - -/* borrowed from mpm_winnt.c */ -extern apr_pool_t *pconf; - -/* Windows 2000 alone supports ChangeServiceConfig2 in order to - * register our server_version string... so we need some fixups - * to avoid binding to that function if we are on WinNT/9x. - */ -static void set_service_description(void) -{ - const char *full_description; - SC_HANDLE schSCManager; - BOOL ret = 0; - - /* Nothing to do if we are a console - */ - if (!mpm_service_name) - return; - - /* Time to fix up the description, upon each successful restart - */ - full_description = ap_get_server_version(); - - if ((osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - && (osver.dwMajorVersion > 4) - && (ChangeServiceConfig2) - && (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT))) - { - SC_HANDLE schService = OpenService(schSCManager, mpm_service_name, - SERVICE_CHANGE_CONFIG); - if (schService) { - /* Cast is necessary, ChangeServiceConfig2 handles multiple - * object types, some volatile, some not. - */ - /* ###: utf-ize */ - if (ChangeServiceConfig2(schService, - 1 /* SERVICE_CONFIG_DESCRIPTION */, - (LPVOID) &full_description)) { - full_description = NULL; - } - CloseServiceHandle(schService); - } - CloseServiceHandle(schSCManager); - } - - if (full_description) - { - char szPath[MAX_PATH]; - ap_regkey_t *svckey; - apr_status_t rv; - - /* Find the Service key that Monitor Applications iterate */ - apr_snprintf(szPath, sizeof(szPath), - "SYSTEM\\CurrentControlSet\\Services\\%s", - mpm_service_name); - rv = ap_regkey_open(&svckey, AP_REGKEY_LOCAL_MACHINE, szPath, - APR_READ | APR_WRITE, pconf); - if (rv != APR_SUCCESS) { - return; - } - /* Attempt to set the Description value for our service */ - ap_regkey_value_set(svckey, "Description", full_description, 0, pconf); - ap_regkey_close(svckey); - } -} - -/* handle the SCM's ControlService() callbacks to our service */ - -static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode) -{ - if (dwCtrlCode == SERVICE_CONTROL_STOP) - { - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 30000); - return; - } - if (dwCtrlCode == SERVICE_APACHE_RESTART) - { - ap_signal_parent(SIGNAL_PARENT_RESTART); - ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000); - return; - } - - ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, NO_ERROR, 0); -} - - -/* service_nt_main_fn is outside of the call stack and outside of the - * primary server thread... so now we _really_ need a placeholder! - * The winnt_rewrite_args has created and shared mpm_new_argv with us. - */ -extern apr_array_header_t *mpm_new_argv; - -/* ###: utf-ize */ -static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv) -{ - const char *ignored; - - /* args and service names live in the same pool */ - mpm_service_set_name(mpm_new_argv->pool, &ignored, argv[0]); - - memset(&globdat.ssStatus, 0, sizeof(globdat.ssStatus)); - globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING; - globdat.ssStatus.dwCheckPoint = 1; - - /* ###: utf-ize */ - if (!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_nt_ctrl))) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Failure registering service handler"); - return; - } - - /* Report status, no errors, and buy 3 more seconds */ - ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000); - - /* We need to append all the command arguments passed via StartService() - * to our running service... which just got here via the SCM... - * but we hvae no interest in argv[0] for the mpm_new_argv list. - */ - if (argc > 1) - { - char **cmb_data; - - mpm_new_argv->nalloc = mpm_new_argv->nelts + argc - 1; - cmb_data = malloc(mpm_new_argv->nalloc * sizeof(const char *)); - - /* mpm_new_argv remains first (of lower significance) */ - memcpy (cmb_data, mpm_new_argv->elts, - mpm_new_argv->elt_size * mpm_new_argv->nelts); - - /* Service args follow from StartService() invocation */ - memcpy (cmb_data + mpm_new_argv->nelts, argv + 1, - mpm_new_argv->elt_size * (argc - 1)); - - /* The replacement arg list is complete */ - mpm_new_argv->elts = (char *)cmb_data; - mpm_new_argv->nelts = mpm_new_argv->nalloc; - } - - /* Let the main thread continue now... but hang on to the - * signal_monitor event so we can take further action - */ - SetEvent(globdat.service_init); - - WaitForSingleObject(globdat.service_term, INFINITE); -} - - -DWORD WINAPI service_nt_dispatch_thread(LPVOID nada) -{ - apr_status_t rv = APR_SUCCESS; - - SERVICE_TABLE_ENTRY dispatchTable[] = - { - { "", service_nt_main_fn }, - { NULL, NULL } - }; - - /* ###: utf-ize */ - if (!StartServiceCtrlDispatcher(dispatchTable)) - { - /* This is a genuine failure of the SCM. */ - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Error starting service control dispatcher"); - } - - return (rv); -} - - -apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, - const char *set_name) -{ - char key_name[MAX_PATH]; - ap_regkey_t *key; - apr_status_t rv; - - /* ### Needs improvement, on Win2K the user can _easily_ - * change the display name to a string that doesn't reflect - * the internal service name + whitespace! - */ - mpm_service_name = apr_palloc(p, strlen(set_name) + 1); - apr_collapse_spaces((char*) mpm_service_name, set_name); - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, APR_READ, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_get(&mpm_display_name, key, "DisplayName", pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - /* Take the given literal name if there is no service entry */ - mpm_display_name = apr_pstrdup(p, set_name); - } - *display_name = mpm_display_name; - return rv; -} - - -apr_status_t mpm_merge_service_args(apr_pool_t *p, - apr_array_header_t *args, - int fixed_args) -{ - apr_array_header_t *svc_args = NULL; - char conf_key[MAX_PATH]; - char **cmb_data; - apr_status_t rv; - ap_regkey_t *key; - - apr_snprintf(conf_key, sizeof(conf_key), SERVICEPARAMS, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, conf_key, APR_READ, p); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_array_get(&svc_args, key, "ConfigArgs", p); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - if (rv == ERROR_FILE_NOT_FOUND) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, - "No ConfigArgs registered for %s, perhaps " - "this service is not installed?", - mpm_service_name); - return APR_SUCCESS; - } - else - return (rv); - } - - if (!svc_args || svc_args->nelts == 0) { - return (APR_SUCCESS); - } - - /* Now we have the mpm_service_name arg, and the mpm_runservice_nt() - * call appended the arguments passed by StartService(), so it's - * time to _prepend_ the default arguments for the server from - * the service's default arguments (all others override them)... - */ - args->nalloc = args->nelts + svc_args->nelts; - cmb_data = malloc(args->nalloc * sizeof(const char *)); - - /* First three args (argv[0], -f, path) remain first */ - memcpy(cmb_data, args->elts, args->elt_size * fixed_args); - - /* Service args follow from service registry array */ - memcpy(cmb_data + fixed_args, svc_args->elts, - svc_args->elt_size * svc_args->nelts); - - /* Remaining new args follow */ - memcpy(cmb_data + fixed_args + svc_args->nelts, - (const char **)args->elts + fixed_args, - args->elt_size * (args->nelts - fixed_args)); - - args->elts = (char *)cmb_data; - args->nelts = args->nalloc; - - return APR_SUCCESS; -} - - -void service_stopped(void) -{ - /* Still have a thread & window to clean up, so signal now */ - if (globdat.service_thread) - { - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - /* Stop logging to the event log */ - mpm_nt_eventlog_stderr_flush(); - - /* Cause the service_nt_main_fn to complete */ - ReleaseMutex(globdat.service_term); - - ReportStatusToSCMgr(SERVICE_STOPPED, // service state - NO_ERROR, // exit code - 0); // wait hint - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - RegisterServiceProcess(0, 0); - PostThreadMessage(globdat.service_thread_id, WM_CLOSE, 0, 0); - } - - WaitForSingleObject(globdat.service_thread, 5000); - CloseHandle(globdat.service_thread); - } -} - - -apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p) -{ - HANDLE hProc = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - HANDLE waitfor[2]; - - /* Prevent holding open the (hidden) console */ - real_exit_code = 0; - - /* GetCurrentThread returns a psuedo-handle, we need - * a real handle for another thread to wait upon. - */ - if (!DuplicateHandle(hProc, hThread, hProc, &(globdat.mpm_thread), - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - return APR_ENOTHREAD; - } - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - globdat.service_init = CreateEvent(NULL, FALSE, FALSE, NULL); - globdat.service_term = CreateMutex(NULL, TRUE, NULL); - if (!globdat.service_init || !globdat.service_term) { - return APR_EGENERAL; - } - - globdat.service_thread = CreateThread(NULL, 0, service_nt_dispatch_thread, - NULL, 0, &globdat.service_thread_id); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - if (!RegisterServiceProcess(0, 1)) - return GetLastError(); - - globdat.service_init = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!globdat.service_init) { - return APR_EGENERAL; - } - - globdat.service_thread = CreateThread(NULL, 0, monitor_service_9x_thread, - (LPVOID) mpm_service_name, 0, - &globdat.service_thread_id); - } - - if (!globdat.service_thread) { - return APR_ENOTHREAD; - } - - waitfor[0] = globdat.service_init; - waitfor[1] = globdat.service_thread; - - /* Wait for controlling thread init or termination */ - if (WaitForMultipleObjects(2, waitfor, FALSE, 10000) != WAIT_OBJECT_0) { - return APR_ENOTHREAD; - } - - atexit(service_stopped); - *display_name = mpm_display_name; - return APR_SUCCESS; -} - - -apr_status_t mpm_service_started(void) -{ - set_service_description(); - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - ReportStatusToSCMgr(SERVICE_RUNNING, // service state - NO_ERROR, // exit code - 0); // wait hint - } - return APR_SUCCESS; -} - - -void mpm_service_stopping(void) -{ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - ReportStatusToSCMgr(SERVICE_STOP_PENDING, // service state - NO_ERROR, // exit code - 30000); // wait hint -} - - -apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, - const char * const * argv, int reconfig) -{ - char key_name[MAX_PATH]; - char exe_path[MAX_PATH]; - char *launch_cmd; - ap_regkey_t *key; - apr_status_t rv; - - fprintf(stderr,reconfig ? "Reconfiguring the %s service\n" - : "Installing the %s service\n", mpm_display_name); - - /* ###: utf-ize */ - if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0) - { - apr_status_t rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "GetModuleFileName failed"); - return rv; - } - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_CREATE_SERVICE); - if (!schSCManager) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to open the WinNT service manager"); - return (rv); - } - - launch_cmd = apr_psprintf(ptemp, "\"%s\" -k runservice", exe_path); - - if (reconfig) { - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_CHANGE_CONFIG); - if (!schService) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR, - apr_get_os_error(), NULL, - "OpenService failed"); - } - /* ###: utf-ize */ - else if (!ChangeServiceConfig(schService, - SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, - SERVICE_ERROR_NORMAL, - launch_cmd, NULL, NULL, - "Tcpip\0Afd\0", NULL, NULL, - mpm_display_name)) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR, - apr_get_os_error(), NULL, - "ChangeServiceConfig failed"); - /* !schService aborts configuration below */ - CloseServiceHandle(schService); - schService = NULL; - } - } - else { - /* RPCSS is the Remote Procedure Call (RPC) Locator required - * for DCOM communication pipes. I am far from convinced we - * should add this to the default service dependencies, but - * be warned that future apache modules or ISAPI dll's may - * depend on it. - */ - /* ###: utf-ize */ - schService = CreateService(schSCManager, // SCManager database - mpm_service_name, // name of service - mpm_display_name, // name to display - SERVICE_ALL_ACCESS, // access required - SERVICE_WIN32_OWN_PROCESS, // service type - SERVICE_AUTO_START, // start type - SERVICE_ERROR_NORMAL, // error control type - launch_cmd, // service's binary - NULL, // no load svc group - NULL, // no tag identifier - "Tcpip\0Afd\0", // dependencies - NULL, // use SYSTEM account - NULL); // no password - - if (!schService) - { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to create WinNT Service Profile"); - CloseServiceHandle(schSCManager); - return (rv); - } - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - /* Store the launch command in the registry */ - launch_cmd = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice", - exe_path, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, SERVICECONFIG9X, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_set(key, mpm_service_name, - launch_cmd, 0, pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to add the RunServices registry entry.", - mpm_display_name); - return (rv); - } - - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to create the registry service key.", - mpm_display_name); - return (rv); - } - rv = ap_regkey_value_set(key, "ImagePath", launch_cmd, 0, pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store ImagePath in the registry.", - mpm_display_name); - ap_regkey_close(key); - return (rv); - } - rv = ap_regkey_value_set(key, "DisplayName", - mpm_display_name, 0, pconf); - ap_regkey_close(key); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store DisplayName in the registry.", - mpm_display_name); - return (rv); - } - } - - set_service_description(); - - /* For both WinNT & Win9x store the service ConfigArgs in the registry... - */ - apr_snprintf(key_name, sizeof(key_name), SERVICEPARAMS, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_array_set(key, "ConfigArgs", argc, argv, pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store the ConfigArgs in the registry.", - mpm_display_name); - return (rv); - } - fprintf(stderr,"The %s service is successfully installed.\n", mpm_display_name); - return APR_SUCCESS; -} - - -apr_status_t mpm_service_uninstall(void) -{ - char key_name[MAX_PATH]; - apr_status_t rv; - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - fprintf(stderr,"Removing the %s service\n", mpm_display_name); - - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_CONNECT); - if (!schSCManager) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to open the WinNT service manager."); - return (rv); - } - - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, DELETE); - - if (!schService) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: OpenService failed", mpm_display_name); - return (rv); - } - - /* assure the service is stopped before continuing - * - * This may be out of order... we might not be able to be - * granted all access if the service is running anyway. - * - * And do we want to make it *this easy* for them - * to uninstall their service unintentionally? - */ - // ap_stop_service(schService); - - if (DeleteService(schService) == 0) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to delete the service.", mpm_display_name); - return (rv); - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - apr_status_t rv2, rv3; - ap_regkey_t *key; - fprintf(stderr,"Removing the %s service\n", mpm_display_name); - - /* TODO: assure the service is stopped before continuing */ - - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, SERVICECONFIG9X, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_remove(key, mpm_service_name, pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to remove the RunServices registry " - "entry.", mpm_display_name); - } - - /* we blast Services/us, not just the Services/us/Parameters branch */ - apr_snprintf(key_name, sizeof(key_name), SERVICEPARAMS, mpm_service_name); - rv2 = ap_regkey_remove(AP_REGKEY_LOCAL_MACHINE, key_name, pconf); - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - rv3 = ap_regkey_remove(AP_REGKEY_LOCAL_MACHINE, key_name, pconf); - rv2 = (rv2 != APR_SUCCESS) ? rv2 : rv3; - if (rv2 != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv2, NULL, - "%s: Failed to remove the service config from the " - "registry.", mpm_display_name); - } - rv = (rv != APR_SUCCESS) ? rv : rv2; - if (rv != APR_SUCCESS) - return rv; - } - fprintf(stderr,"The %s service has been removed successfully.\n", mpm_display_name); - return APR_SUCCESS; -} - - -/* signal_service_transition is a simple thunk to signal the service - * and monitor its successful transition. If the signal passed is 0, - * then the caller is assumed to already have performed some service - * operation to be monitored (such as StartService), and no actual - * ControlService signal is sent. - */ - -static int signal_service_transition(SC_HANDLE schService, DWORD signal, DWORD pending, DWORD complete) -{ - if (signal && !ControlService(schService, signal, &globdat.ssStatus)) - return FALSE; - - do { - Sleep(1000); - if (!QueryServiceStatus(schService, &globdat.ssStatus)) - return FALSE; - } while (globdat.ssStatus.dwCurrentState == pending); - - return (globdat.ssStatus.dwCurrentState == complete); -} - - -apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, - const char * const * argv) -{ - apr_status_t rv; - - fprintf(stderr,"Starting the %s service\n", mpm_display_name); - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - char **start_argv; - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_CONNECT); - if (!schSCManager) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to open the WinNT service manager"); - return (rv); - } - - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_START | SERVICE_QUERY_STATUS); - if (!schService) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to open the service.", mpm_display_name); - CloseServiceHandle(schSCManager); - return (rv); - } - - if (QueryServiceStatus(schService, &globdat.ssStatus) - && (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, - "Service %s is already started!", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return 0; - } - - start_argv = malloc((argc + 1) * sizeof(const char **)); - memcpy(start_argv, argv, argc * sizeof(const char **)); - start_argv[argc] = NULL; - - rv = APR_EINIT; - /* ###: utf-ize */ - if (StartService(schService, argc, start_argv) - && signal_service_transition(schService, 0, /* test only */ - SERVICE_START_PENDING, - SERVICE_RUNNING)) - rv = APR_SUCCESS; - - if (rv != APR_SUCCESS) - rv = apr_get_os_error(); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - STARTUPINFO si; /* Filled in prior to call to CreateProcess */ - PROCESS_INFORMATION pi; /* filled in on call to CreateProcess */ - char exe_path[MAX_PATH]; - char exe_cmd[MAX_PATH * 4]; - char *next_arg; - int i; - - /* Locate the active top level window named service_name - * provided the class is ApacheWin95ServiceMonitor - */ - if (FindWindow("ApacheWin95ServiceMonitor", mpm_service_name)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, - "Service %s is already started!", mpm_display_name); - return 0; - } - - /* This may not appear intuitive, but Win9x will not allow a process - * to detach from the console without releasing the entire console. - * Ergo, we must spawn a new process for the service to get back our - * console window. - * The config is pre-flighted, so there should be no danger of failure. - */ - - if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0) - { - apr_status_t rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "GetModuleFileName failed"); - return rv; - } - - apr_snprintf(exe_cmd, sizeof(exe_cmd), - "\"%s\" -n %s -k runservice", - exe_path, mpm_service_name); - next_arg = strchr(exe_cmd, '\0'); - for (i = 0; i < argc; ++i) { - apr_snprintf(next_arg, sizeof(exe_cmd) - (next_arg - exe_cmd), - " \"%s\"", argv[i]); - next_arg = strchr(exe_cmd, '\0'); - } - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; /* This might be redundant */ - - rv = APR_EINIT; - if (CreateProcess(NULL, exe_cmd, NULL, NULL, FALSE, - DETACHED_PROCESS, /* Creation flags */ - NULL, NULL, &si, &pi)) - { - DWORD code; - while (GetExitCodeProcess(pi.hProcess, &code) == STILL_ACTIVE) { - if (FindWindow("ApacheWin95ServiceMonitor", mpm_service_name)) { - rv = APR_SUCCESS; - break; - } - Sleep (1000); - } - } - - if (rv != APR_SUCCESS) - rv = apr_get_os_error(); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - if (rv == APR_SUCCESS) - fprintf(stderr,"The %s service is running.\n", mpm_display_name); - else - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "%s: Failed to start the service process.", - mpm_display_name); - - return rv; -} - - -/* signal is zero to stop, non-zero for restart */ - -void mpm_signal_service(apr_pool_t *ptemp, int signal) -{ - int success = FALSE; - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, NULL, // default machine & database - SC_MANAGER_CONNECT); - - if (!schSCManager) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Failed to open the NT Service Manager"); - return; - } - - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_INTERROGATE | SERVICE_QUERY_STATUS | - SERVICE_USER_DEFINED_CONTROL | - SERVICE_START | SERVICE_STOP); - - if (schService == NULL) { - /* Could not open the service */ - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Failed to open the %s Service", mpm_display_name); - CloseServiceHandle(schSCManager); - return; - } - - if (!QueryServiceStatus(schService, &globdat.ssStatus)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Query of Service %s failed", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - - if (!signal && (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)) { - fprintf(stderr,"The %s service is not started.\n", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - - fprintf(stderr,"The %s service is %s.\n", mpm_display_name, - signal ? "restarting" : "stopping"); - - if (!signal) - success = signal_service_transition(schService, - SERVICE_CONTROL_STOP, - SERVICE_STOP_PENDING, - SERVICE_STOPPED); - else if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) { - mpm_service_start(ptemp, 0, NULL); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - else - success = signal_service_transition(schService, - SERVICE_APACHE_RESTART, - SERVICE_START_PENDING, - SERVICE_RUNNING); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* !isWindowsNT() */ - { - DWORD service_pid; - HANDLE hwnd; - char prefix[20]; - /* Locate the active top level window named service_name - * provided the class is ApacheWin95ServiceMonitor - */ - hwnd = FindWindow("ApacheWin95ServiceMonitor", mpm_service_name); - if (hwnd && GetWindowThreadProcessId(hwnd, &service_pid)) - globdat.ssStatus.dwCurrentState = SERVICE_RUNNING; - else - { - globdat.ssStatus.dwCurrentState = SERVICE_STOPPED; - if (!signal) { - fprintf(stderr,"The %s service is not started.\n", mpm_display_name); - return; - } - } - - fprintf(stderr,"The %s service is %s.\n", mpm_display_name, - signal ? "restarting" : "stopping"); - - apr_snprintf(prefix, sizeof(prefix), "ap%ld", (long)service_pid); - setup_signal_names(prefix); - - if (!signal) - { - int ticks = 60; - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - while (--ticks) - { - if (!IsWindow(hwnd)) { - success = TRUE; - break; - } - Sleep(1000); - } - } - else /* !stop */ - { - /* TODO: Aught to add a little test to the restart logic, and - * store the restart counter in the window's user dword. - * Then we can hang on and report a successful restart. But - * that's a project for another day. - */ - if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) { - mpm_service_start(ptemp, 0, NULL); - return; - } - else { - success = TRUE; - ap_signal_parent(SIGNAL_PARENT_RESTART); - } - } - } - - if (success) - fprintf(stderr,"The %s service has %s.\n", mpm_display_name, - signal ? "restarted" : "stopped"); - else - fprintf(stderr,"Failed to %s the %s service.\n", - signal ? "restart" : "stop", mpm_display_name); -} diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/.deps b/rubbos/app/httpd-2.0.64/server/mpm/worker/.deps deleted file mode 100644 index e69de29b..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/.deps +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/fdqueue.o b/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/fdqueue.o Binary files differdeleted file mode 100644 index fb4a5ad1..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/fdqueue.o +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/libworker.a b/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/libworker.a Binary files differdeleted file mode 100644 index b315573e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/libworker.a +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/libworker.la b/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/libworker.la deleted file mode 100644 index 464032f9..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/libworker.la +++ /dev/null @@ -1,35 +0,0 @@ -# libworker.la - a libtool library file -# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='' - -# Names of this library. -library_names='' - -# The name of the static archive. -old_library='libworker.a' - -# Libraries that this one depends upon. -dependency_libs=' -L/bottlenecks/rubbos/app/httpd-2.0.64/srclib/apr-util/xml/expat/lib' - -# Version information for libworker. -current= -age= -revision= - -# Is this an already installed library? -installed=no - -# Should we warn about portability when linking against -modules? -shouldnotlink=no - -# Files to dlopen/dlpreopen -dlopen='' -dlpreopen='' - -# Directory that this library needs to be installed in: -libdir='' diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/pod.o b/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/pod.o Binary files differdeleted file mode 100644 index 42e89371..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/pod.o +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/worker.o b/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/worker.o Binary files differdeleted file mode 100644 index dc560c2b..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/.libs/worker.o +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/Makefile b/rubbos/app/httpd-2.0.64/server/mpm/worker/Makefile deleted file mode 100644 index 6c812571..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -top_srcdir = /bottlenecks/rubbos/app/httpd-2.0.64 -top_builddir = /bottlenecks/rubbos/app/httpd-2.0.64 -srcdir = /bottlenecks/rubbos/app/httpd-2.0.64/server/mpm/worker -builddir = /bottlenecks/rubbos/app/httpd-2.0.64/server/mpm/worker -VPATH = /bottlenecks/rubbos/app/httpd-2.0.64/server/mpm/worker - -LTLIBRARY_NAME = libworker.la -LTLIBRARY_SOURCES = worker.c fdqueue.c pod.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/Makefile.in b/rubbos/app/httpd-2.0.64/server/mpm/worker/Makefile.in deleted file mode 100644 index b45b8483..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libworker.la -LTLIBRARY_SOURCES = worker.c fdqueue.c pod.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/config5.m4 b/rubbos/app/httpd-2.0.64/server/mpm/worker/config5.m4 deleted file mode 100644 index cc131348..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/config5.m4 +++ /dev/null @@ -1,6 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "worker" ; then - AC_CHECK_FUNCS(pthread_kill) - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.c b/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.c deleted file mode 100644 index 17a819bf..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.c +++ /dev/null @@ -1,317 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "fdqueue.h" - -struct fd_queue_info_t { - int idlers; - apr_thread_mutex_t *idlers_mutex; - apr_thread_cond_t *wait_for_idler; - int terminated; - int max_idlers; - apr_pool_t **recycled_pools; - int num_recycled; -}; - -static apr_status_t queue_info_cleanup(void *data_) -{ - fd_queue_info_t *qi = data_; - int i; - apr_thread_cond_destroy(qi->wait_for_idler); - apr_thread_mutex_destroy(qi->idlers_mutex); - for (i = 0; i < qi->num_recycled; i++) { - apr_pool_destroy(qi->recycled_pools[i]); - } - return APR_SUCCESS; -} - -apr_status_t ap_queue_info_create(fd_queue_info_t **queue_info, - apr_pool_t *pool, int max_idlers) -{ - apr_status_t rv; - fd_queue_info_t *qi; - - qi = apr_palloc(pool, sizeof(*qi)); - memset(qi, 0, sizeof(*qi)); - - rv = apr_thread_mutex_create(&qi->idlers_mutex, APR_THREAD_MUTEX_DEFAULT, - pool); - if (rv != APR_SUCCESS) { - return rv; - } - rv = apr_thread_cond_create(&qi->wait_for_idler, pool); - if (rv != APR_SUCCESS) { - return rv; - } - qi->recycled_pools = (apr_pool_t **)apr_palloc(pool, max_idlers * - sizeof(apr_pool_t *)); - qi->num_recycled = 0; - qi->max_idlers = max_idlers; - apr_pool_cleanup_register(pool, qi, queue_info_cleanup, - apr_pool_cleanup_null); - - *queue_info = qi; - - return APR_SUCCESS; -} - -apr_status_t ap_queue_info_set_idle(fd_queue_info_t *queue_info, - apr_pool_t *pool_to_recycle) -{ - apr_status_t rv; - rv = apr_thread_mutex_lock(queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - AP_DEBUG_ASSERT(queue_info->idlers >= 0); - AP_DEBUG_ASSERT(queue_info->num_recycled < queue_info->max_idlers); - if (pool_to_recycle) { - queue_info->recycled_pools[queue_info->num_recycled++] = - pool_to_recycle; - } - if (queue_info->idlers++ == 0) { - /* Only signal if we had no idlers before. */ - apr_thread_cond_signal(queue_info->wait_for_idler); - } - rv = apr_thread_mutex_unlock(queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - return APR_SUCCESS; -} - -apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t *queue_info, - apr_pool_t **recycled_pool) -{ - apr_status_t rv; - *recycled_pool = NULL; - rv = apr_thread_mutex_lock(queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - AP_DEBUG_ASSERT(queue_info->idlers >= 0); - while ((queue_info->idlers == 0) && (!queue_info->terminated)) { - rv = apr_thread_cond_wait(queue_info->wait_for_idler, - queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - apr_status_t rv2; - rv2 = apr_thread_mutex_unlock(queue_info->idlers_mutex); - if (rv2 != APR_SUCCESS) { - return rv2; - } - return rv; - } - } - queue_info->idlers--; /* Oh, and idler? Let's take 'em! */ - if (queue_info->num_recycled) { - *recycled_pool = - queue_info->recycled_pools[--queue_info->num_recycled]; - } - rv = apr_thread_mutex_unlock(queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - else if (queue_info->terminated) { - return APR_EOF; - } - else { - return APR_SUCCESS; - } -} - -apr_status_t ap_queue_info_term(fd_queue_info_t *queue_info) -{ - apr_status_t rv; - rv = apr_thread_mutex_lock(queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - queue_info->terminated = 1; - apr_thread_cond_broadcast(queue_info->wait_for_idler); - rv = apr_thread_mutex_unlock(queue_info->idlers_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - return APR_SUCCESS; -} - -/** - * Detects when the fd_queue_t is full. This utility function is expected - * to be called from within critical sections, and is not threadsafe. - */ -#define ap_queue_full(queue) ((queue)->nelts == (queue)->bounds) - -/** - * Detects when the fd_queue_t is empty. This utility function is expected - * to be called from within critical sections, and is not threadsafe. - */ -#define ap_queue_empty(queue) ((queue)->nelts == 0) - -/** - * Callback routine that is called to destroy this - * fd_queue_t when its pool is destroyed. - */ -static apr_status_t ap_queue_destroy(void *data) -{ - fd_queue_t *queue = data; - - /* Ignore errors here, we can't do anything about them anyway. - * XXX: We should at least try to signal an error here, it is - * indicative of a programmer error. -aaron */ - apr_thread_cond_destroy(queue->not_empty); - apr_thread_mutex_destroy(queue->one_big_mutex); - - return APR_SUCCESS; -} - -/** - * Initialize the fd_queue_t. - */ -apr_status_t ap_queue_init(fd_queue_t *queue, int queue_capacity, apr_pool_t *a) -{ - int i; - apr_status_t rv; - - if ((rv = apr_thread_mutex_create(&queue->one_big_mutex, - APR_THREAD_MUTEX_DEFAULT, a)) != APR_SUCCESS) { - return rv; - } - if ((rv = apr_thread_cond_create(&queue->not_empty, a)) != APR_SUCCESS) { - return rv; - } - - queue->data = apr_palloc(a, queue_capacity * sizeof(fd_queue_elem_t)); - queue->bounds = queue_capacity; - queue->nelts = 0; - - /* Set all the sockets in the queue to NULL */ - for (i = 0; i < queue_capacity; ++i) - queue->data[i].sd = NULL; - - apr_pool_cleanup_register(a, queue, ap_queue_destroy, apr_pool_cleanup_null); - - return APR_SUCCESS; -} - -/** - * Push a new socket onto the queue. Blocks if the queue is full. Once - * the push operation has completed, it signals other threads waiting - * in ap_queue_pop() that they may continue consuming sockets. - */ -apr_status_t ap_queue_push(fd_queue_t *queue, apr_socket_t *sd, apr_pool_t *p) -{ - fd_queue_elem_t *elem; - apr_status_t rv; - - if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - - AP_DEBUG_ASSERT(!queue->terminated); - AP_DEBUG_ASSERT(!ap_queue_full(queue)); - - elem = &queue->data[queue->nelts]; - elem->sd = sd; - elem->p = p; - queue->nelts++; - - apr_thread_cond_signal(queue->not_empty); - - if ((rv = apr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - - return APR_SUCCESS; -} - -/** - * Retrieves the next available socket from the queue. If there are no - * sockets available, it will block until one becomes available. - * Once retrieved, the socket is placed into the address specified by - * 'sd'. - */ -apr_status_t ap_queue_pop(fd_queue_t *queue, apr_socket_t **sd, apr_pool_t **p) -{ - fd_queue_elem_t *elem; - apr_status_t rv; - - if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - - /* Keep waiting until we wake up and find that the queue is not empty. */ - if (ap_queue_empty(queue)) { - if (!queue->terminated) { - apr_thread_cond_wait(queue->not_empty, queue->one_big_mutex); - } - /* If we wake up and it's still empty, then we were interrupted */ - if (ap_queue_empty(queue)) { - rv = apr_thread_mutex_unlock(queue->one_big_mutex); - if (rv != APR_SUCCESS) { - return rv; - } - if (queue->terminated) { - return APR_EOF; /* no more elements ever again */ - } - else { - return APR_EINTR; - } - } - } - - elem = &queue->data[--queue->nelts]; - *sd = elem->sd; - *p = elem->p; -#ifdef AP_DEBUG - elem->sd = NULL; - elem->p = NULL; -#endif /* AP_DEBUG */ - - rv = apr_thread_mutex_unlock(queue->one_big_mutex); - return rv; -} - -apr_status_t ap_queue_interrupt_all(fd_queue_t *queue) -{ - apr_status_t rv; - - if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - apr_thread_cond_broadcast(queue->not_empty); - if ((rv = apr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - return APR_SUCCESS; -} - -apr_status_t ap_queue_term(fd_queue_t *queue) -{ - apr_status_t rv; - - if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - /* we must hold one_big_mutex when setting this... otherwise, - * we could end up setting it and waking everybody up just after a - * would-be popper checks it but right before they block - */ - queue->terminated = 1; - if ((rv = apr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) { - return rv; - } - return ap_queue_interrupt_all(queue); -} diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.h b/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.h deleted file mode 100644 index 6dd55e03..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FDQUEUE_H -#define FDQUEUE_H -#include "httpd.h" -#include <stdlib.h> -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <apr_thread_mutex.h> -#include <apr_thread_cond.h> -#include <sys/types.h> -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#include <apr_errno.h> - -typedef struct fd_queue_info_t fd_queue_info_t; - -apr_status_t ap_queue_info_create(fd_queue_info_t **queue_info, - apr_pool_t *pool, int max_idlers); -apr_status_t ap_queue_info_set_idle(fd_queue_info_t *queue_info, - apr_pool_t *pool_to_recycle); -apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t *queue_info, - apr_pool_t **recycled_pool); -apr_status_t ap_queue_info_term(fd_queue_info_t *queue_info); - -struct fd_queue_elem_t { - apr_socket_t *sd; - apr_pool_t *p; -}; -typedef struct fd_queue_elem_t fd_queue_elem_t; - -struct fd_queue_t { - fd_queue_elem_t *data; - int nelts; - int bounds; - apr_thread_mutex_t *one_big_mutex; - apr_thread_cond_t *not_empty; - int terminated; -}; -typedef struct fd_queue_t fd_queue_t; - -apr_status_t ap_queue_init(fd_queue_t *queue, int queue_capacity, apr_pool_t *a); -apr_status_t ap_queue_push(fd_queue_t *queue, apr_socket_t *sd, apr_pool_t *p); -apr_status_t ap_queue_pop(fd_queue_t *queue, apr_socket_t **sd, apr_pool_t **p); -apr_status_t ap_queue_interrupt_all(fd_queue_t *queue); -apr_status_t ap_queue_term(fd_queue_t *queue); - -#endif /* FDQUEUE_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.lo b/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.lo deleted file mode 100644 index 88d30c88..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.lo +++ /dev/null @@ -1,12 +0,0 @@ -# fdqueue.lo - a libtool object file -# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# Name of the PIC object. -pic_object='.libs/fdqueue.o' - -# Name of the non-PIC object. -non_pic_object='fdqueue.o' - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.o b/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.o Binary files differdeleted file mode 100644 index fb4a5ad1..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/fdqueue.o +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/libworker.la b/rubbos/app/httpd-2.0.64/server/mpm/worker/libworker.la deleted file mode 100644 index 464032f9..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/libworker.la +++ /dev/null @@ -1,35 +0,0 @@ -# libworker.la - a libtool library file -# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='' - -# Names of this library. -library_names='' - -# The name of the static archive. -old_library='libworker.a' - -# Libraries that this one depends upon. -dependency_libs=' -L/bottlenecks/rubbos/app/httpd-2.0.64/srclib/apr-util/xml/expat/lib' - -# Version information for libworker. -current= -age= -revision= - -# Is this an already installed library? -installed=no - -# Should we warn about portability when linking against -modules? -shouldnotlink=no - -# Files to dlopen/dlpreopen -dlopen='' -dlpreopen='' - -# Directory that this library needs to be installed in: -libdir='' diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/worker/mpm.h deleted file mode 100644 index 31830c6c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/mpm.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "scoreboard.h" -#include "unixd.h" - -#ifndef APACHE_MPM_WORKER_H -#define APACHE_MPM_WORKER_H - -#define WORKER_MPM - -#define MPM_NAME "Worker" - -#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT -#define AP_MPM_WANT_PROCESS_CHILD_STATUS -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_LOCKFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -#define AP_MPM_WANT_SIGNAL_SERVER -#define AP_MPM_WANT_SET_MAX_MEM_FREE -#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER -#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK - -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -#define MPM_ACCEPT_FUNC unixd_accept - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; - -#endif /* APACHE_MPM_WORKER_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/worker/mpm_default.h deleted file mode 100644 index d5a33989..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/mpm_default.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#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 3 -#endif - -/* 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 3 -#endif - -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 25 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/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/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.c b/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.c deleted file mode 100644 index 3a9a266e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.c +++ /dev/null @@ -1,112 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "pod.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod) -{ - apr_status_t rv; - - *pod = apr_palloc(p, sizeof(**pod)); - rv = apr_file_pipe_create(&((*pod)->pod_in), &((*pod)->pod_out), p); - if (rv != APR_SUCCESS) { - return rv; - } -/* - apr_file_pipe_timeout_set((*pod)->pod_in, 0); -*/ - (*pod)->p = p; - - /* close these before exec. */ - apr_file_unset_inherit((*pod)->pod_in); - apr_file_unset_inherit((*pod)->pod_out); - - return APR_SUCCESS; -} - -AP_DECLARE(int) ap_mpm_pod_check(ap_pod_t *pod) -{ - char c; - apr_os_file_t fd; - int rc; - - /* we need to surface EINTR so we'll have to grab the - * native file descriptor and do the OS read() ourselves - */ - apr_os_file_get(&fd, pod->pod_in); - rc = read(fd, &c, 1); - if (rc == 1) { - switch(c) { - case RESTART_CHAR: - return AP_RESTART; - case GRACEFUL_CHAR: - return AP_GRACEFUL; - } - } - return AP_NORESTART; -} - -AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod) -{ - apr_status_t rv; - - rv = apr_file_close(pod->pod_out); - if (rv != APR_SUCCESS) { - return rv; - } - - rv = apr_file_close(pod->pod_in); - if (rv != APR_SUCCESS) { - return rv; - } - return rv; -} - -static apr_status_t pod_signal_internal(ap_pod_t *pod, int graceful) -{ - apr_status_t rv; - char char_of_death = graceful ? GRACEFUL_CHAR : RESTART_CHAR; - apr_size_t one = 1; - - do { - rv = apr_file_write(pod->pod_out, &char_of_death, &one); - } while (APR_STATUS_IS_EINTR(rv)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, - "write pipe_of_death"); - } - return rv; -} - -AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod, int graceful) -{ - return pod_signal_internal(pod, graceful); -} - -AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num, int graceful) -{ - int i; - apr_status_t rv = APR_SUCCESS; - - for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = pod_signal_internal(pod, graceful); - } -} - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.h b/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.h deleted file mode 100644 index 21651e6f..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr.h" -#include "apr_strings.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_main.h" -#include "mpm.h" -#include "mpm_common.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "mpm_default.h" - -#define RESTART_CHAR '$' -#define GRACEFUL_CHAR '!' - -#define AP_RESTART 0 -#define AP_GRACEFUL 1 - -typedef struct ap_pod_t ap_pod_t; - -struct ap_pod_t { - apr_file_t *pod_in; - apr_file_t *pod_out; - apr_pool_t *p; -}; - -AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod); -AP_DECLARE(int) ap_mpm_pod_check(ap_pod_t *pod); -AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod); -AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod, int graceful); -AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num, int graceful); diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.lo b/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.lo deleted file mode 100644 index b284c939..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.lo +++ /dev/null @@ -1,12 +0,0 @@ -# pod.lo - a libtool object file -# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# Name of the PIC object. -pic_object='.libs/pod.o' - -# Name of the non-PIC object. -non_pic_object='pod.o' - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.o b/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.o Binary files differdeleted file mode 100644 index 42e89371..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/pod.o +++ /dev/null diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.c b/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.c deleted file mode 100644 index 6e0da647..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.c +++ /dev/null @@ -1,2136 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* The purpose of this MPM is to fix the design flaws in the threaded - * model. Because of the way that pthreads and mutex locks interact, - * it is basically impossible to cleanly gracefully shutdown a child - * process if multiple threads are all blocked in accept. This model - * fixes those problems. - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" -#include "apr_thread_mutex.h" -#include "apr_proc_mutex.h" -#include "apr_poll.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if APR_HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifdef HAVE_SYS_PROCESSOR_H -#include <sys/processor.h> /* for bindprocessor() */ -#endif - -#if !APR_HAS_THREADS -#error The Worker MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.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 "pod.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "scoreboard.h" -#include "fdqueue.h" -#include "mpm_default.h" - -#include <signal.h> -#include <limits.h> /* for INT_MAX */ - -/* 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. - */ -#ifndef DEFAULT_SERVER_LIMIT -#define DEFAULT_SERVER_LIMIT 16 -#endif - -/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_SERVER_LIMIT -#define MAX_SERVER_LIMIT 20000 -#endif - -/* Limit on the threads per process. Clients will be locked out if more than - * this * 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. - */ -#ifndef DEFAULT_THREAD_LIMIT -#define DEFAULT_THREAD_LIMIT 64 -#endif - -/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want - * some sort of compile-time limit to help catch typos. - */ -#ifndef MAX_THREAD_LIMIT -#define MAX_THREAD_LIMIT 20000 -#endif - -/* - * Actual definitions of config globals - */ - -int ap_threads_per_child = 0; /* Worker threads per child */ -static int ap_daemons_to_start = 0; -static int min_spare_threads = 0; -static int max_spare_threads = 0; -static int ap_daemons_limit = 0; -static int server_limit = DEFAULT_SERVER_LIMIT; -static int first_server_limit; -static int thread_limit = DEFAULT_THREAD_LIMIT; -static int first_thread_limit; -static int changed_limit_at_restart; -static int dying = 0; -static int workers_may_exit = 0; -static int start_thread_may_exit = 0; -static int listener_may_exit = 0; -static int requests_this_child; -static int num_listensocks = 0; -static int resource_shortage = 0; -static fd_queue_t *worker_queue; -static fd_queue_info_t *worker_queue_info; -static int mpm_state = AP_MPMQ_STARTING; -static int sick_child_detected; - -/* The structure used to pass unique initialization info to each thread */ -typedef struct { - int pid; - int tid; - int sd; -} proc_info; - -/* Structure used to pass information to the thread responsible for - * creating the rest of the threads. - */ -typedef struct { - apr_thread_t **threads; - apr_thread_t *listener; - int child_num_arg; - apr_threadattr_t *threadattr; -} thread_starter; - -#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t) - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We - * use this value to optimize routines that have to scan the entire - * scoreboard. - */ -int ap_max_daemons_limit = -1; - -static ap_pod_t *pod; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* The worker MPM respects a couple of runtime flags that can aid - * in debugging. Setting the -DNO_DETACH flag will prevent the root process - * from detaching from its controlling terminal. Additionally, setting - * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the - * child_main loop running in the process which originally started up. - * This gives you a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -static int one_process = 0; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main - thread. Use this instead */ -static pid_t parent_pid; -static apr_os_thread_t *listener_os_thread; - -/* Locks for accept serialization */ -static apr_proc_mutex_t *accept_mutex; - -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS) -#else -#define SAFE_ACCEPT(stmt) (stmt) -#endif - -/* The LISTENER_SIGNAL signal will be sent from the main thread to the - * listener thread to wake it up for graceful termination (what a child - * process from an old generation does when the admin does "apachectl - * graceful"). This signal will be blocked in all threads of a child - * process except for the listener thread. - */ -#define LISTENER_SIGNAL SIGHUP - -/* An array of socket descriptors in use by each thread used to - * perform a non-graceful (forced) shutdown of the server. */ -static apr_socket_t **worker_sockets; - -static void close_worker_sockets(void) -{ - int i; - for (i = 0; i < ap_threads_per_child; i++) { - if (worker_sockets[i]) { - apr_socket_close(worker_sockets[i]); - worker_sockets[i] = NULL; - } - } -} - -static void wakeup_listener(void) -{ - listener_may_exit = 1; - if (!listener_os_thread) { - /* XXX there is an obscure path that this doesn't handle perfectly: - * right after listener thread is created but before - * listener_os_thread is set, the first worker thread hits an - * error and starts graceful termination - */ - return; - } - /* - * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all - * platforms and wake up the listener thread since it is the only thread - * with SIGHUP unblocked, but that doesn't work on Linux - */ -#ifdef HAVE_PTHREAD_KILL - pthread_kill(*listener_os_thread, LISTENER_SIGNAL); -#else - kill(ap_my_pid, LISTENER_SIGNAL); -#endif -} - -#define ST_INIT 0 -#define ST_GRACEFUL 1 -#define ST_UNGRACEFUL 2 - -static int terminate_mode = ST_INIT; - -static void signal_threads(int mode) -{ - if (terminate_mode == mode) { - return; - } - terminate_mode = mode; - mpm_state = AP_MPMQ_STOPPING; - - /* in case we weren't called from the listener thread, wake up the - * listener thread - */ - wakeup_listener(); - - /* for ungraceful termination, let the workers exit now; - * for graceful termination, the listener thread will notify the - * workers to exit once it has stopped accepting new connections - */ - if (mode == ST_UNGRACEFUL) { - workers_may_exit = 1; - ap_queue_interrupt_all(worker_queue); - ap_queue_info_term(worker_queue_info); - close_worker_sockets(); /* forcefully kill all current connections */ - } -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = server_limit; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = thread_limit; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = min_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = max_spare_threads; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = ap_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) __attribute__ ((noreturn)); -static void clean_child_exit(int code) -{ - mpm_state = AP_MPMQ_STOPPING; - if (pchild) { - apr_pool_destroy(pchild); - } - exit(code); -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -static volatile int child_fatal; -ap_generation_t volatile ap_my_generation; - -/* - * 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. - */ - -static void ap_start_shutdown(void) -{ - mpm_state = AP_MPMQ_STOPPING; - 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 */ -static void ap_start_restart(int graceful) -{ - mpm_state = AP_MPMQ_STOPPING; - 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 == AP_SIG_GRACEFUL); -} - -static void set_signals(void) -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; -#endif - - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } - -#ifndef NO_USE_SIGACTION - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGINT)"); -#endif -#ifdef SIGXCPU - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXCPU, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXCPU)"); -#endif -#ifdef SIGXFSZ - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXFSZ, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGXFSZ)"); -#endif -#ifdef SIGPIPE - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy - * processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(SIGHUP)"); - if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "sigaction(" AP_SIG_GRACEFUL_STRING ")"); -#else - if (!one_process) { -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef AP_SIG_GRACEFUL - apr_signal(AP_SIG_GRACEFUL, restart); -#endif /* AP_SIG_GRACEFUL */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) - /* XXX this is really a bad confusing obsolete name - * maybe it should be ap_mpm_process_exiting? - */ -{ - /* note: for a graceful termination, listener_may_exit will be set before - * workers_may_exit, so check listener_may_exit - */ - return listener_may_exit; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, - int my_thread_num, apr_bucket_alloc_t *bucket_alloc) -{ - conn_rec *current_conn; - long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num); - int csd; - ap_sb_handle_t *sbh; - - ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num); - apr_os_sock_get(&csd, sock); - - current_conn = ap_run_create_connection(p, ap_server_conf, sock, - conn_id, sbh, bucket_alloc); - if (current_conn) { - ap_process_connection(current_conn, sock); - ap_lingering_close(current_conn); - } -} - -/* requests_this_child has gone to zero or below. See if the admin coded - "MaxRequestsPerChild 0", and keep going in that case. Doing it this way - simplifies the hot path in worker_thread */ -static void check_infinite_requests(void) -{ - if (ap_max_requests_per_child) { - signal_threads(ST_GRACEFUL); - } - else { - /* wow! if you're executing this code, you may have set a record. - * either this child process has served over 2 billion requests, or - * you're running a threaded 2.0 on a 16 bit machine. - * - * I'll buy pizza and beers at Apachecon for the first person to do - * the former without cheating (dorking with INT_MAX, or running with - * uncommitted performance patches, for example). - * - * for the latter case, you probably deserve a beer too. Greg Ames - */ - - requests_this_child = INT_MAX; /* keep going */ - } -} - -static void unblock_signal(int sig) -{ - sigset_t sig_mask; - - sigemptyset(&sig_mask); - sigaddset(&sig_mask, sig); -#if defined(SIGPROCMASK_SETS_THREAD_MASK) - sigprocmask(SIG_UNBLOCK, &sig_mask, NULL); -#else - pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL); -#endif -} - -static void dummy_signal_handler(int sig) -{ - /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall, - * then we don't need this goofy function. - */ -} - -static void *listener_thread(apr_thread_t *thd, void * dummy) -{ - proc_info * ti = dummy; - int process_slot = ti->pid; - apr_pool_t *tpool = apr_thread_pool_get(thd); - void *csd = NULL; - apr_pool_t *ptrans = NULL; /* Pool for per-transaction stuff */ - int n; - apr_pollfd_t *pollset; - apr_status_t rv; - ap_listen_rec *lr, *last_lr = ap_listeners; - int have_idle_worker = 0; - - free(ti); - - apr_poll_setup(&pollset, num_listensocks, tpool); - for(lr = ap_listeners ; lr != NULL ; lr = lr->next) - apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); - - /* Unblock the signal used to wake this thread up, and set a handler for - * it. - */ - unblock_signal(LISTENER_SIGNAL); - apr_signal(LISTENER_SIGNAL, dummy_signal_handler); - - /* TODO: Switch to a system where threads reuse the results from earlier - poll calls - manoj */ - while (1) { - /* TODO: requests_this_child should be synchronized - aaron */ - if (requests_this_child <= 0) { - check_infinite_requests(); - } - if (listener_may_exit) break; - - if (!have_idle_worker) { - /* the following pops a recycled ptrans pool off a stack - * if there is one, in addition to reserving a worker thread - */ - rv = ap_queue_info_wait_for_idler(worker_queue_info, - &ptrans); - if (APR_STATUS_IS_EOF(rv)) { - break; /* we've been signaled to die now */ - } - else if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_queue_info_wait failed. Attempting to " - " shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - break; - } - have_idle_worker = 1; - } - - /* We've already decremented the idle worker count inside - * ap_queue_info_wait_for_idler. */ - - if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (listener_may_exit) { - break; - } - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_lock failed. Attempting to shutdown " - "process gracefully."); - signal_threads(ST_GRACEFUL); - break; /* skip the lock release */ - } - - if (!ap_listeners->next) { - /* Only one listener, so skip the poll */ - lr = ap_listeners; - } - else { - while (!listener_may_exit) { - apr_status_t ret; - apr_int16_t event; - - ret = apr_poll(pollset, num_listensocks, &n, -1); - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - - /* apr_pollset_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - signal_threads(ST_GRACEFUL); - } - - if (listener_may_exit) break; - - /* find a listener */ - lr = last_lr; - do { - lr = lr->next; - if (lr == NULL) { - lr = ap_listeners; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, lr->sd, pollset); - if (event & APR_POLLIN) { - last_lr = lr; - goto got_fd; - } - } while (lr != last_lr); - } - } - got_fd: - if (!listener_may_exit) { - if (ptrans == NULL) { - /* we can't use a recycled transaction pool this time. - * create a new transaction pool */ - apr_allocator_t *allocator; - - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - apr_pool_create_ex(&ptrans, NULL, NULL, allocator); - apr_allocator_owner_set(allocator, ptrans); - } - apr_pool_tag(ptrans, "transaction"); - rv = lr->accept_func(&csd, lr, ptrans); - /* later we trash rv and rely on csd to indicate success/failure */ - AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd); - - if (rv == APR_EGENERAL) { - /* E[NM]FILE, ENOMEM, etc */ - resource_shortage = 1; - signal_threads(ST_GRACEFUL); - } - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (listener_may_exit) { - break; - } - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - } - if (csd != NULL) { - rv = ap_queue_push(worker_queue, csd, ptrans); - if (rv) { - /* trash the connection; we couldn't queue the connected - * socket to a worker - */ - apr_socket_close(csd); - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "ap_queue_push failed"); - } - else { - have_idle_worker = 0; - } - } - } - else { - if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) - != APR_SUCCESS) { - int level = APLOG_EMERG; - - if (ap_scoreboard_image->parent[process_slot].generation != - ap_scoreboard_image->global->running_generation) { - level = APLOG_DEBUG; /* common to get these at restart time */ - } - ap_log_error(APLOG_MARK, level, rv, ap_server_conf, - "apr_proc_mutex_unlock failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - } - break; - } - } - - ap_queue_term(worker_queue); - dying = 1; - ap_scoreboard_image->parent[process_slot].quiescing = 1; - - /* wake up the main thread */ - kill(ap_my_pid, SIGTERM); - - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -/* XXX For ungraceful termination/restart, we definitely don't want to - * wait for active connections to finish but we may want to wait - * for idle workers to get out of the queue code and release mutexes, - * since those mutexes are cleaned up pretty soon and some systems - * may not react favorably (i.e., segfault) if operations are attempted - * on cleaned-up mutexes. - */ -static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy) -{ - proc_info * ti = dummy; - int process_slot = ti->pid; - int thread_slot = ti->tid; - apr_socket_t *csd = NULL; - apr_bucket_alloc_t *bucket_alloc; - apr_pool_t *last_ptrans = NULL; - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_status_t rv; - int is_idle = 0; - - free(ti); - - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL); - - while (!workers_may_exit) { - if (!is_idle) { - rv = ap_queue_info_set_idle(worker_queue_info, last_ptrans); - last_ptrans = NULL; - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "ap_queue_info_set_idle failed. Attempting to " - "shutdown process gracefully."); - signal_threads(ST_GRACEFUL); - break; - } - is_idle = 1; - } - - ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL); -worker_pop: - if (workers_may_exit) { - break; - } - rv = ap_queue_pop(worker_queue, &csd, &ptrans); - - if (rv != APR_SUCCESS) { - /* We get APR_EOF during a graceful shutdown once all the connections - * accepted by this server process have been handled. - */ - if (APR_STATUS_IS_EOF(rv)) { - break; - } - /* We get APR_EINTR whenever ap_queue_pop() has been interrupted - * from an explicit call to ap_queue_interrupt_all(). This allows - * us to unblock threads stuck in ap_queue_pop() when a shutdown - * is pending. - * - * If workers_may_exit is set and this is ungraceful termination/ - * restart, we are bound to get an error on some systems (e.g., - * AIX, which sanity-checks mutex operations) since the queue - * may have already been cleaned up. Don't log the "error" if - * workers_may_exit is set. - */ - else if (APR_STATUS_IS_EINTR(rv)) { - goto worker_pop; - } - /* We got some other error. */ - else if (!workers_may_exit) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "ap_queue_pop failed"); - } - continue; - } - is_idle = 0; - worker_sockets[thread_slot] = csd; - bucket_alloc = apr_bucket_alloc_create(ptrans); - process_socket(ptrans, csd, process_slot, thread_slot, bucket_alloc); - worker_sockets[thread_slot] = NULL; - requests_this_child--; /* FIXME: should be synchronized - aaron */ - apr_pool_clear(ptrans); - last_ptrans = ptrans; - } - - ap_update_child_status_from_indexes(process_slot, thread_slot, - (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL); - - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - return 1; - } - return 0; -} - -static void create_listener_thread(thread_starter *ts) -{ - int my_child_num = ts->child_num_arg; - apr_threadattr_t *thread_attr = ts->threadattr; - proc_info *my_info; - apr_status_t rv; - - my_info = (proc_info *)malloc(sizeof(proc_info)); - my_info->pid = my_child_num; - my_info->tid = -1; /* listener thread doesn't have a thread slot */ - my_info->sd = 0; - rv = apr_thread_create(&ts->listener, thread_attr, listener_thread, - my_info, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create listener thread"); - /* let the parent decide how bad this really is */ - clean_child_exit(APEXIT_CHILDSICK); - } - apr_os_thread_get(&listener_os_thread, ts->listener); -} - -/* XXX under some circumstances not understood, children can get stuck - * in start_threads forever trying to take over slots which will - * never be cleaned up; for now there is an APLOG_DEBUG message issued - * every so often when this condition occurs - */ -static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) -{ - thread_starter *ts = dummy; - apr_thread_t **threads = ts->threads; - apr_threadattr_t *thread_attr = ts->threadattr; - int child_num_arg = ts->child_num_arg; - int my_child_num = child_num_arg; - proc_info *my_info; - apr_status_t rv; - int i; - int threads_created = 0; - int listener_started = 0; - int loops; - int prev_threads_created; - - /* We must create the fd queues before we start up the listener - * and worker threads. */ - worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue)); - rv = ap_queue_init(worker_queue, ap_threads_per_child, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "ap_queue_init() failed"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - rv = ap_queue_info_create(&worker_queue_info, pchild, - ap_threads_per_child); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "ap_queue_info_create() failed"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - worker_sockets = apr_pcalloc(pchild, ap_threads_per_child - * sizeof(apr_socket_t *)); - - loops = prev_threads_created = 0; - while (1) { - /* ap_threads_per_child does not include the listener thread */ - for (i = 0; i < ap_threads_per_child; i++) { - int status = ap_scoreboard_image->servers[child_num_arg][i].status; - - if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { - continue; - } - - 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->pid = my_child_num; - my_info->tid = i; - my_info->sd = 0; - - /* We are creating threads right now */ - ap_update_child_status_from_indexes(my_child_num, i, - SERVER_STARTING, NULL); - /* We let each thread update its own scoreboard entry. This is - * done because it lets us deal with tid better. - */ - rv = apr_thread_create(&threads[i], thread_attr, - worker_thread, my_info, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker thread"); - /* let the parent decide how bad this really is */ - clean_child_exit(APEXIT_CHILDSICK); - } - threads_created++; - } - /* Start the listener only when there are workers available */ - if (!listener_started && threads_created) { - create_listener_thread(ts); - listener_started = 1; - } - if (start_thread_may_exit || threads_created == ap_threads_per_child) { - break; - } - /* wait for previous generation to clean up an entry */ - apr_sleep(apr_time_from_sec(1)); - ++loops; - if (loops % 120 == 0) { /* every couple of minutes */ - if (prev_threads_created == threads_created) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "child %" APR_PID_T_FMT " isn't taking over " - "slots very quickly (%d of %d)", - ap_my_pid, threads_created, ap_threads_per_child); - } - prev_threads_created = threads_created; - } - } - - /* What state should this child_main process be listed as in the - * scoreboard...? - * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, - * (request_rec *) NULL); - * - * This state should be listed separately in the scoreboard, in some kind - * of process_status, not mixed in with the worker threads' status. - * "life_status" is almost right, but it's in the worker's structure, and - * the name could be clearer. gla - */ - apr_thread_exit(thd, APR_SUCCESS); - return NULL; -} - -static void join_workers(apr_thread_t *listener, apr_thread_t **threads) -{ - int i; - apr_status_t rv, thread_rv; - - if (listener) { - int iter; - - /* deal with a rare timing window which affects waking up the - * listener thread... if the signal sent to the listener thread - * is delivered between the time it verifies that the - * listener_may_exit flag is clear and the time it enters a - * blocking syscall, the signal didn't do any good... work around - * that by sleeping briefly and sending it again - */ - - iter = 0; - while (iter < 10 && -#ifdef HAVE_PTHREAD_KILL - pthread_kill(*listener_os_thread, 0) -#else - kill(ap_my_pid, 0) -#endif - == 0) { - /* listener not dead yet */ - apr_sleep(apr_time_make(0, 500000)); - wakeup_listener(); - ++iter; - } - if (iter >= 10) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "the listener thread didn't exit"); - } - else { - rv = apr_thread_join(&thread_rv, listener); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join listener thread"); - } - } - } - - for (i = 0; i < ap_threads_per_child; i++) { - if (threads[i]) { /* if we ever created this thread */ - rv = apr_thread_join(&thread_rv, threads[i]); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join worker " - "thread %d", - i); - } - } - } -} - -static void join_start_thread(apr_thread_t *start_thread_id) -{ - apr_status_t rv, thread_rv; - - start_thread_may_exit = 1; /* tell it to give up in case it is still - * trying to take over slots from a - * previous generation - */ - rv = apr_thread_join(&thread_rv, start_thread_id); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "apr_thread_join: unable to join the start " - "thread"); - } -} - -static void child_main(int child_num_arg) -{ - apr_thread_t **threads; - apr_status_t rv; - thread_starter *ts; - apr_threadattr_t *thread_attr; - apr_thread_t *start_thread_id; - - mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this - * child initializes - */ - ap_my_pid = getpid(); - ap_fatal_signal_child_setup(ap_server_conf); - apr_pool_create(&pchild, pconf); - - /*stuff to do before we switch id's, so we have permissions.*/ - ap_reopen_scoreboard(pchild, NULL, 0); - - rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, - pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (unixd_setup_child()) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /* done with init critical section */ - - /* Just use the standard apr_setup_signal_thread to block all signals - * from being received. The child processes no longer use signals for - * any communication with the parent process. - */ - rv = apr_setup_signal_thread(); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize signal thread"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (ap_max_requests_per_child) { - requests_this_child = ap_max_requests_per_child; - } - else { - /* coding a value of zero means infinity */ - requests_this_child = INT_MAX; - } - - /* Setup worker threads */ - - /* clear the storage; we may not create all our threads immediately, - * and we want a 0 entry to indicate a thread which was not created - */ - threads = (apr_thread_t **)calloc(1, - sizeof(apr_thread_t *) * ap_threads_per_child); - if (threads == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, - "malloc: out of memory"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts)); - - apr_threadattr_create(&thread_attr, pchild); - /* 0 means PTHREAD_CREATE_JOINABLE */ - apr_threadattr_detach_set(thread_attr, 0); - - ts->threads = threads; - ts->listener = NULL; - ts->child_num_arg = child_num_arg; - ts->threadattr = thread_attr; - - rv = apr_thread_create(&start_thread_id, thread_attr, start_threads, - ts, pchild); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker thread"); - /* let the parent decide how bad this really is */ - clean_child_exit(APEXIT_CHILDSICK); - } - - mpm_state = AP_MPMQ_RUNNING; - - /* If we are only running in one_process mode, we will want to - * still handle signals. */ - if (one_process) { - /* Block until we get a terminating signal. */ - apr_signal_thread(check_signal); - /* make sure the start thread has finished; signal_threads() - * and join_workers() depend on that - */ - /* XXX join_start_thread() won't be awakened if one of our - * threads encounters a critical error and attempts to - * shutdown this child - */ - join_start_thread(start_thread_id); - signal_threads(ST_UNGRACEFUL); /* helps us terminate a little more - * quickly than the dispatch of the signal thread - * beats the Pipe of Death and the browsers - */ - /* A terminating signal was received. Now join each of the - * workers to clean them up. - * If the worker already exited, then the join frees - * their resources and returns. - * If the worker hasn't exited, then this blocks until - * they have (then cleans up). - */ - join_workers(ts->listener, threads); - } - else { /* !one_process */ - /* remove SIGTERM from the set of blocked signals... if one of - * the other threads in the process needs to take us down - * (e.g., for MaxRequestsPerChild) it will send us SIGTERM - */ - unblock_signal(SIGTERM); - apr_signal(SIGTERM, dummy_signal_handler); - /* Watch for any messages from the parent over the POD */ - while (1) { - rv = ap_mpm_pod_check(pod); - if (rv == AP_NORESTART) { - /* see if termination was triggered while we slept */ - switch(terminate_mode) { - case ST_GRACEFUL: - rv = AP_GRACEFUL; - break; - case ST_UNGRACEFUL: - rv = AP_RESTART; - break; - } - } - if (rv == AP_GRACEFUL || rv == AP_RESTART) { - /* make sure the start thread has finished; - * signal_threads() and join_workers depend on that - */ - join_start_thread(start_thread_id); - signal_threads(rv == AP_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); - break; - } - } - - /* A terminating signal was received. Now join each of the - * workers to clean them up. - * If the worker already exited, then the join frees - * their resources and returns. - * If the worker hasn't exited, then this blocks until - * they have (then cleans up). - */ - join_workers(ts->listener, threads); - } - - free(threads); - - clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_scoreboard_image->parent[slot].pid = getpid(); - child_main(slot); - } - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "fork: Unable to fork new process"); - - /* fork didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL); - - /* 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. */ - apr_sleep(apr_time_from_sec(10)); - - return -1; - } - - if (!pid) { -#ifdef HAVE_BINDPROCESSOR - /* By default, AIX binds to a single processor. This bit unbinds - * children which will then bind to another CPU. - */ - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, - ap_server_conf, - "processor unbind failed %d", status); -#endif - RAISE_SIGSTOP(MAKE_CHILD); - - apr_signal(SIGTERM, just_die); - child_main(slot); - - clean_child_exit(0); - } - /* else */ - if (ap_scoreboard_image->parent[slot].pid != 0) { - /* This new child process is squatting on the scoreboard - * entry owned by an exiting child process, which cannot - * exit until all active requests complete. - * Don't forget about this exiting child process, or we - * won't be able to kill it if it doesn't exit by the - * time the server is shut down. - */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "taking over scoreboard slot from %" APR_PID_T_FMT "%s", - ap_scoreboard_image->parent[slot].pid, - ap_scoreboard_image->parent[slot].quiescing ? - " (quiescing)" : ""); - ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid); - } - ap_scoreboard_image->parent[slot].quiescing = 0; - ap_scoreboard_image->parent[slot].pid = pid; - return 0; -} - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->parent[i].pid != 0) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * idle_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 idle_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, j; - int idle_thread_count; - worker_score *ws; - process_score *ps; - int free_length; - int totally_free_length = 0; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - int active_thread_count = 0; - - /* initialize the free_list */ - free_length = 0; - - idle_thread_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - for (i = 0; i < ap_daemons_limit; ++i) { - /* Initialization to satisfy the compiler. It doesn't know - * that ap_threads_per_child is always > 0 */ - int status = SERVER_DEAD; - int any_dying_threads = 0; - int any_dead_threads = 0; - int all_dead_threads = 1; - - if (i >= ap_max_daemons_limit && totally_free_length == idle_spawn_rate) - break; - ps = &ap_scoreboard_image->parent[i]; - for (j = 0; j < ap_threads_per_child; j++) { - ws = &ap_scoreboard_image->servers[i][j]; - status = ws->status; - - /* XXX any_dying_threads is probably no longer needed GLA */ - any_dying_threads = any_dying_threads || - (status == SERVER_GRACEFUL); - any_dead_threads = any_dead_threads || (status == SERVER_DEAD); - all_dead_threads = all_dead_threads && - (status == SERVER_DEAD || - status == SERVER_GRACEFUL); - - /* We consider a starting server as idle because we started it - * at least a cycle ago, and if it still hasn't finished starting - * then we're just going to swamp things worse by forking more. - * So we hopefully won't need to fork more if we count it. - * This depends on the ordering of SERVER_READY and SERVER_STARTING. - */ - if (ps->pid != 0) { /* XXX just set all_dead_threads in outer for - loop if no pid? not much else matters */ - if (status <= SERVER_READY && status != SERVER_DEAD && - !ps->quiescing && - ps->generation == ap_my_generation) { - ++idle_thread_count; - } - if (status >= SERVER_READY && status < SERVER_GRACEFUL) { - ++active_thread_count; - } - } - } - if (any_dead_threads && totally_free_length < idle_spawn_rate - && free_length < MAX_SPAWN_RATE - && (!ps->pid /* no process in the slot */ - || ps->quiescing)) { /* or at least one is going away */ - if (all_dead_threads) { - /* great! we prefer these, because the new process can - * start more threads sooner. So prioritize this slot - * by putting it ahead of any slots with active threads. - * - * first, make room by moving a slot that's potentially still - * in use to the end of the array - */ - free_slots[free_length] = free_slots[totally_free_length]; - free_slots[totally_free_length++] = i; - } - else { - /* slot is still in use - back of the bus - */ - free_slots[free_length] = i; - } - ++free_length; - } - /* XXX if (!ps->quiescing) is probably more reliable GLA */ - if (!any_dying_threads) { - last_non_dead = i; - ++total_non_dead; - } - } - - if (sick_child_detected) { - if (active_thread_count > 0) { - /* some child processes appear to be working. don't kill the - * whole server. - */ - sick_child_detected = 0; - } - else { - /* looks like a basket case. give up. - */ - shutdown_pending = 1; - child_fatal = 1; - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, - ap_server_conf, - "No active workers found..." - " Apache is exiting!"); - /* the child already logged the failure details */ - return; - } - } - - ap_max_daemons_limit = last_non_dead + 1; - - if (idle_thread_count > max_spare_threads) { - /* Kill off one child */ - ap_mpm_pod_signal(pod, TRUE); - idle_spawn_rate = 1; - } - else if (idle_thread_count < min_spare_threads) { - /* terminate the free list */ - if (free_length == 0) { - /* only report this condition once */ - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - ap_server_conf, - "server reached MaxClients setting, consider" - " raising the MaxClients setting"); - reported = 1; - } - idle_spawn_rate = 1; - } - else { - if (free_length > idle_spawn_rate) { - free_length = idle_spawn_rate; - } - if (idle_spawn_rate >= 8) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - ap_server_conf, - "server seems busy, (you may need " - "to increase StartServers, ThreadsPerChild " - "or Min/MaxSpareThreads), " - "spawning %d children, there are around %d idle " - "threads, and %d total children", free_length, - idle_thread_count, total_non_dead); - } - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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 (idle_spawn_rate < MAX_SPAWN_RATE) { - idle_spawn_rate *= 2; - } - } - } - else { - idle_spawn_rate = 1; - } -} - -static void server_main_loop(int remaining_children_to_start) -{ - int child_slot; - apr_exit_why_e exitwhy; - int status, processed_status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); - - if (pid.pid != -1) { - processed_status = ap_process_child_status(&pid, exitwhy, status); - if (processed_status == APEXIT_CHILDFATAL) { - shutdown_pending = 1; - child_fatal = 1; - return; - } - else if (processed_status == APEXIT_CHILDSICK) { - /* tell perform_idle_server_maintenance to check into this - * on the next timer pop - */ - sick_child_detected = 1; - } - /* non-fatal death... note that it's gone in the scoreboard. */ - child_slot = find_child_by_pid(&pid); - if (child_slot >= 0) { - for (i = 0; i < ap_threads_per_child; i++) - ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD, - (request_rec *) NULL); - - ap_scoreboard_image->parent[child_slot].pid = 0; - ap_scoreboard_image->parent[child_slot].quiescing = 0; - if (processed_status == APEXIT_CHILDSICK) { - /* resource shortage, minimize the fork rate */ - idle_spawn_rate = 1; - } - else if (remaining_children_to_start - && child_slot < ap_daemons_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } - } - else if (ap_unregister_extra_mpm_process(pid.pid) == 1) { - /* handled */ -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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_WARNING, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)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_children_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_children(remaining_children_to_start); - remaining_children_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(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - apr_status_t rv; - - ap_log_pid(pconf, ap_pid_fname); - - first_server_limit = server_limit; - first_thread_limit = thread_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit or ThreadLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - - /* Initialize cross-process accept lock */ - ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, - ap_server_root_relative(_pconf, ap_lock_fname), - ap_my_pid); - - rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname, - ap_accept_lock_mech, _pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create accept lock"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - -#if APR_USE_SYSVSEM_SERIALIZE - if (ap_accept_lock_mech == APR_LOCK_DEFAULT || - ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#else - if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -#endif - rv = unixd_set_proc_mutex_perms(accept_mutex); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't set permissions on cross-process lock; " - "check User and Group directives"); - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - } - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - mpm_state = AP_MPMQ_STOPPING; - return 1; - } - /* fix the generation number in the global score; we just got a new, - * cleared scoreboard - */ - ap_scoreboard_image->global->running_generation = ap_my_generation; - } - - set_signals(); - /* Don't thrash... */ - if (max_spare_threads < min_spare_threads + ap_threads_per_child) - max_spare_threads = min_spare_threads + ap_threads_per_child; - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least daemons_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_children_to_start = ap_daemons_to_start; - if (remaining_children_to_start > ap_daemons_limit) { - remaining_children_to_start = ap_daemons_limit; - } - if (!is_graceful) { - startup_children(remaining_children_to_start); - remaining_children_to_start = 0; - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); -#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "AcceptMutex: %s (default: %s)", - apr_proc_mutex_name(accept_mutex), - apr_proc_mutex_defname()); -#endif - restart_pending = shutdown_pending = 0; - mpm_state = AP_MPMQ_RUNNING; - - server_main_loop(remaining_children_to_start); - mpm_state = AP_MPMQ_STOPPING; - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - * (By "gracefully" we don't mean graceful in the same sense as - * "apachectl graceful" where we allow old connections to finish.) - */ - ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE); - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - - if (!child_fatal) { - /* 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_INFO, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, - ap_server_conf, "caught SIGTERM, shutting down"); - } - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); - /* wake up the children...time to die. But we'll have more soon */ - ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE); - - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - } - 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. - */ - ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE); - - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - return 0; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - apr_status_t rv; - - pconf = p; - ap_server_conf = s; - - if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - - if (!one_process) { - if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); - return DONE; - } - } - return OK; -} - -static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach, debug, foreground; - ap_directive_t *pdir; - ap_directive_t *max_clients = NULL; - apr_status_t rv; - - mpm_state = AP_MPMQ_STARTING; - - /* make sure that "ThreadsPerChild" gets set before "MaxClients" */ - for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) { - if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) { - if (!max_clients) { - break; /* we're in the clear, got ThreadsPerChild first */ - } - else { - /* now to swap the data */ - ap_directive_t temp; - - temp.directive = pdir->directive; - temp.args = pdir->args; - /* Make sure you don't change 'next', or you may get loops! */ - /* XXX: first_child, parent, and data can never be set - * for these directives, right? -aaron */ - temp.filename = pdir->filename; - temp.line_num = pdir->line_num; - - pdir->directive = max_clients->directive; - pdir->args = max_clients->args; - pdir->filename = max_clients->filename; - pdir->line_num = max_clients->line_num; - - max_clients->directive = temp.directive; - max_clients->args = temp.args; - max_clients->filename = temp.filename; - max_clients->line_num = temp.line_num; - break; - } - } - else if (!max_clients - && strncasecmp(pdir->directive, "MaxClients", 10) == 0) { - max_clients = pdir; - } - } - - debug = ap_exists_config_define("DEBUG"); - - if (debug) { - foreground = one_process = 1; - no_detach = 0; - } - else { - one_process = ap_exists_config_define("ONE_PROCESS"); - no_detach = ap_exists_config_define("NO_DETACH"); - foreground = ap_exists_config_define("FOREGROUND"); - } - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !foreground) { - rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND - : APR_PROC_DETACH_DAEMONIZE); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "apr_proc_detach failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - parent_pid = ap_my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_START_DAEMON; - min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - ap_daemons_limit = server_limit; - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static void worker_hooks(apr_pool_t *p) -{ - /* The worker open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - one_process = 0; - - ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); - /* we need to set the MPM state before other pre-config hooks use MPM query - * to retrieve it, so register as REALLY_FIRST - */ - ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); -} - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, - const 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, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, - const 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_max_clients (cmd_parms *cmd, void *dummy, - const char *arg) -{ - int max_clients; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - /* It is ok to use ap_threads_per_child here because we are - * sure that it gets set before MaxClients in the pre_config stage. */ - max_clients = atoi(arg); - if (max_clients < ap_threads_per_child) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) must be at least as large", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " as ThreadsPerChild (%d). Automatically", - ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " increasing MaxClients to %d.", - ap_threads_per_child); - max_clients = ap_threads_per_child; - } - ap_daemons_limit = max_clients / ap_threads_per_child; - if ((max_clients > 0) && (max_clients % ap_threads_per_child)) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) is not an integer multiple", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " of ThreadsPerChild (%d), lowering MaxClients to %d", - ap_threads_per_child, - ap_daemons_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " for a maximum of %d child processes,", - ap_daemons_limit); - max_clients = ap_daemons_limit * ap_threads_per_child; - } - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d would require %d servers,", - max_clients, ap_daemons_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " and would exceed the ServerLimit value of %d.", - server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " Automatically lowering MaxClients to %d. To increase,", - server_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " please see the ServerLimit directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, - const 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 > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "threads, lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_server_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } - return NULL; -} - -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_thread_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d servers,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } - return NULL; -} - -static const command_rec worker_cmds[] = { -UNIX_DAEMON_COMMANDS, -LISTEN_COMMANDS, -AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle threads, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle threads"), -AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, - "Maximum number of threads alive at the same time"), -AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, - "Maximum number of child processes for this run of Apache"), -AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, - "Maximum number of worker threads per child process for this run of Apache - Upper limit for ThreadsPerChild"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_worker_module = { - MPM20_MODULE_STUFF, - ap_mpm_rewrite_args, /* 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 */ - worker_cmds, /* command apr_table_t */ - worker_hooks /* register_hooks */ -}; - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.lo b/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.lo deleted file mode 100644 index 83f3b7ff..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.lo +++ /dev/null @@ -1,12 +0,0 @@ -# worker.lo - a libtool object file -# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18) -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# Name of the PIC object. -pic_object='.libs/worker.o' - -# Name of the non-PIC object. -non_pic_object='worker.o' - diff --git a/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.o b/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.o Binary files differdeleted file mode 100644 index dc560c2b..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/worker/worker.o +++ /dev/null |