beos.c revision 1ce78cf71b5baaf2c1ab48e818cb1f2397df5010
e609c337f729875bc20e01096c7e610f45356f54nilgun/* Licensed to the Apache Software Foundation (ASF) under one or more
e609c337f729875bc20e01096c7e610f45356f54nilgun * contributor license agreements. See the NOTICE file distributed with
e609c337f729875bc20e01096c7e610f45356f54nilgun * this work for additional information regarding copyright ownership.
e609c337f729875bc20e01096c7e610f45356f54nilgun * The ASF licenses this file to You under the Apache License, Version 2.0
e609c337f729875bc20e01096c7e610f45356f54nilgun * (the "License"); you may not use this file except in compliance with
e609c337f729875bc20e01096c7e610f45356f54nilgun * the License. You may obtain a copy of the License at
e609c337f729875bc20e01096c7e610f45356f54nilgun * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distributed under the License is distributed on an "AS IS" BASIS,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen/* The BeOS MPM!
e609c337f729875bc20e01096c7e610f45356f54nilgun * This is a single process, with multiple worker threads.
e609c337f729875bc20e01096c7e610f45356f54nilgun * Under testing I found that given the inability of BeOS to handle threads
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * and forks it didn't make sense to try and have a set of "children" threads
e609c337f729875bc20e01096c7e610f45356f54nilgun * that spawned the "worker" threads, so just missed out the middle mand and
e609c337f729875bc20e01096c7e610f45356f54nilgun * somehow arrived here.
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * For 2.1 this has been rewritten to have simpler logic, though there is still
e609c337f729875bc20e01096c7e610f45356f54nilgun * some simplification that can be done. It's still a work in progress!
e609c337f729875bc20e01096c7e610f45356f54nilgun * TODO Items
e609c337f729875bc20e01096c7e610f45356f54nilgun * - on exit most worker threads segfault trying to access a kernel page.
e609c337f729875bc20e01096c7e610f45356f54nilgun/* Limit on the total --- clients will be locked out if more servers than
e609c337f729875bc20e01096c7e610f45356f54nilgun * this are needed. It is intended solely to keep the server from crashing
e609c337f729875bc20e01096c7e610f45356f54nilgun * when things get out of hand.
e609c337f729875bc20e01096c7e610f45356f54nilgun * We keep a hard maximum number of servers, for two reasons:
e609c337f729875bc20e01096c7e610f45356f54nilgun * 1) in case something goes seriously wrong, we want to stop the server starting
e609c337f729875bc20e01096c7e610f45356f54nilgun * threads ad infinitum and crashing the server (remember that BeOS has a 192
91f378b5a10f2d83820902ed10ba7967a3920c18nilgun * thread per team limit).
e609c337f729875bc20e01096c7e610f45356f54nilgun * 2) it keeps the size of the scoreboard file small
e609c337f729875bc20e01096c7e610f45356f54nilgun * enough that we can read the whole thing without worrying too much about
e609c337f729875bc20e01096c7e610f45356f54nilgun * the overhead.
e609c337f729875bc20e01096c7e610f45356f54nilgun/* we only ever have 1 main process running... */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun/* Limit on the threads per process. Clients will be locked out if more than
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * this * HARD_SERVER_LIMIT are needed.
e609c337f729875bc20e01096c7e610f45356f54nilgun * We keep this for one reason it keeps the size of the scoreboard file small
e609c337f729875bc20e01096c7e610f45356f54nilgun * enough that we can read the whole thing without worrying too much about
e609c337f729875bc20e01096c7e610f45356f54nilgun * the overhead.
e609c337f729875bc20e01096c7e610f45356f54nilgun * Actual definitions of config globals
e609c337f729875bc20e01096c7e610f45356f54nilgun * The max child slot ever assigned, preserved across restarts. Necessary
e609c337f729875bc20e01096c7e610f45356f54nilgun * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We use
e609c337f729875bc20e01096c7e610f45356f54nilgun * this value to optimize routines that have to scan the entire scoreboard.
e609c337f729875bc20e01096c7e610f45356f54nilgun/* one_process */
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int one_process = 0;
e609c337f729875bc20e01096c7e610f45356f54nilgun/* When a worker thread gets to the end of it's life it dies with an
e609c337f729875bc20e01096c7e610f45356f54nilgun * exit value of the code supplied to this function. The thread has
e609c337f729875bc20e01096c7e610f45356f54nilgun * already had check_restart() registered to be called when dying, so
e609c337f729875bc20e01096c7e610f45356f54nilgun * we don't concern ourselves with restarting at all here. We do however
e609c337f729875bc20e01096c7e610f45356f54nilgun * mark the scoreboard slot as belonging to a dead server and zero out
e609c337f729875bc20e01096c7e610f45356f54nilgun * it's thread_id.
e609c337f729875bc20e01096c7e610f45356f54nilgun * TODO - use the status we set to determine if we need to restart the
e609c337f729875bc20e01096c7e610f45356f54nilgun (void) ap_update_child_status_from_indexes(0, slot, SERVER_DEAD,
e609c337f729875bc20e01096c7e610f45356f54nilgun/*****************************************************************
e609c337f729875bc20e01096c7e610f45356f54nilgun * Connection structures and accounting...
e609c337f729875bc20e01096c7e610f45356f54nilgun/* volatile just in case */
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int volatile shutdown_pending;
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int volatile restart_pending;
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int volatile is_graceful;
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic int volatile child_fatal;
e609c337f729875bc20e01096c7e610f45356f54nilgun * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
e609c337f729875bc20e01096c7e610f45356f54nilgun * functions to initiate shutdown or restart without relying on signals.
e609c337f729875bc20e01096c7e610f45356f54nilgun * Previously this was initiated in sig_term() and restart() signal handlers,
e609c337f729875bc20e01096c7e610f45356f54nilgun * but we want to be able to start a shutdown/restart from other sources --
e609c337f729875bc20e01096c7e610f45356f54nilgun * e.g. on Win32, from the service manager. Now the service manager can
e609c337f729875bc20e01096c7e610f45356f54nilgun * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
e609c337f729875bc20e01096c7e610f45356f54nilgun * these functions can also be called by the child processes, since global
e609c337f729875bc20e01096c7e610f45356f54nilgun * variables are no longer used to pass on the required action to the parent.
e609c337f729875bc20e01096c7e610f45356f54nilgun * These should only be called from the parent process itself, since the
e609c337f729875bc20e01096c7e610f45356f54nilgun * parent process will use the shutdown_pending and restart_pending variables
e609c337f729875bc20e01096c7e610f45356f54nilgun * to determine whether to shutdown or restart. The child process should
e609c337f729875bc20e01096c7e610f45356f54nilgun * call signal_parent() directly to tell the parent to die -- this will
e609c337f729875bc20e01096c7e610f45356f54nilgun * cause neither of those variable to be set, which the parent will
e609c337f729875bc20e01096c7e610f45356f54nilgun * assume means something serious is wrong (which it will be, for the
e609c337f729875bc20e01096c7e610f45356f54nilgun * child to force an exit) and so do an exit anyway.
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic void ap_start_shutdown(void)
e609c337f729875bc20e01096c7e610f45356f54nilgun /* If the user tries to shut us down twice in quick succession then we
e609c337f729875bc20e01096c7e610f45356f54nilgun * may well get triggered while we are working through previous attempt
e609c337f729875bc20e01096c7e610f45356f54nilgun * to shutdown. We won't worry about even reporting it as it seems a little
e609c337f729875bc20e01096c7e610f45356f54nilgun * pointless.
e609c337f729875bc20e01096c7e610f45356f54nilgun/* do a graceful restart if graceful == 1 */
e609c337f729875bc20e01096c7e610f45356f54nilgun /* Probably not an error - don't bother reporting it */
91f378b5a10f2d83820902ed10ba7967a3920c18nilgun/* sig_coredump attempts to handle all the potential signals we
e609c337f729875bc20e01096c7e610f45356f54nilgun * may get that should result in a core dump. This is called from
e609c337f729875bc20e01096c7e610f45356f54nilgun * the signal handler routine, so when we enter we are essentially blocked
e609c337f729875bc20e01096c7e610f45356f54nilgun * on the signal. Once we exit we will allow the signal to be processed by
e609c337f729875bc20e01096c7e610f45356f54nilgun * system, which may or may not produce a .core file. All this function does
e609c337f729875bc20e01096c7e610f45356f54nilgun * is try and respect the users wishes about where that file should be
e609c337f729875bc20e01096c7e610f45356f54nilgun * located (chdir) and then signal the parent with the signal.
e609c337f729875bc20e01096c7e610f45356f54nilgun * If we called abort() the parent would only see SIGABRT which doesn't provide
e609c337f729875bc20e01096c7e610f45356f54nilgun * as much information.
e609c337f729875bc20e01096c7e610f45356f54nilgun/* Handle queries about our inner workings... */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgunAP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun/* This accepts a connection and allows us to handle the error codes better than
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * the previous code, while also making it more obvious.
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgunstatic apr_status_t beos_accept(void **accepted, ap_listen_rec *lr, apr_pool_t *ptrans)
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* This switch statement provides us with better error details. */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * When the network layer has been shut down, there
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * is not much use in simply exiting: the parent
e609c337f729875bc20e01096c7e610f45356f54nilgun * would simply re-create us (and we'd fail again).
e609c337f729875bc20e01096c7e610f45356f54nilgun * Use the CHILDFATAL code to tear the server down.
e609c337f729875bc20e01096c7e610f45356f54nilgun * @@@ Martin's idea for possible improvement:
e609c337f729875bc20e01096c7e610f45356f54nilgun * A different approach would be to define
e609c337f729875bc20e01096c7e610f45356f54nilgun * a new APEXIT_NETDOWN exit code, the reception
e609c337f729875bc20e01096c7e610f45356f54nilgun * of which would make the parent shutdown all
e609c337f729875bc20e01096c7e610f45356f54nilgun * children, then idle-loop until it detected that
e609c337f729875bc20e01096c7e610f45356f54nilgun * the network is up again, and restart the children.
e609c337f729875bc20e01096c7e610f45356f54nilgun * Ben Hyde noted that temporary ENETDOWN situations
e609c337f729875bc20e01096c7e610f45356f54nilgun * occur in mobile IP.
e609c337f729875bc20e01096c7e610f45356f54nilgun ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
e609c337f729875bc20e01096c7e610f45356f54nilgun "apr_socket_accept: giving up.");
e609c337f729875bc20e01096c7e610f45356f54nilgun#endif /*ENETDOWN*/
e609c337f729875bc20e01096c7e610f45356f54nilgun ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung "apr_socket_accept: (client socket)");
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohstatic void tell_workers_to_exit(void)
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh for (i = 0 ; i < ap_max_child_assigned; i++){
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh if (apr_socket_sendto(udp_sock, udp_sa, 0, "die!", &len) != APR_SUCCESS)
5effc8b39fae5cd169d17f342bfc265705840014rbowenstatic void set_signals(void)
if (!one_process) {
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
int ap_graceful_stop_signalled(void)
return is_graceful;
int last_poll_idx = 0;
int requests_this_child = 0;
int this_worker_should_exit = 0;
if (!one_process) {
while (!this_worker_should_exit) {
void *csd;
if ((ap_max_requests_per_thread > 0
last_poll_idx = 0;
goto got_a_black_spot;
goto got_fd;
current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, worker_slot, sbh, bucket_alloc);
if (current_conn) {
if (ap_my_generation !=
if (one_process) {
set_signals();
(void *)slot);
if (make_worker(i) < 0)
#ifndef MAX_SPAWN_RATE
static int hold_off_on_exponential_spawning;
static void perform_idle_server_maintenance(void)
int free_length;
free_length = 0;
for (i = 0; i < ap_thread_limit; ++i) {
++free_length;
last_non_dead = i;
if (free_length > 0) {
for (i = 0; i < free_length; ++i) {
int child_slot;
int status;
for (i = 0; i < ap_max_child_assigned; ++i) {
child_slot = i;
if (child_slot >= 0) {
else if (is_graceful) {
else if (remaining_threads_to_start) {
int remaining_threads_to_start, i,j;
ap_server_conf = s;
!= APR_SUCCESS){
if (!is_graceful) {
for (i = 0; i < HARD_SERVER_LIMIT; i++) {
for (j = 0;j < HARD_THREAD_LIMIT; j++)
set_signals();
if (!one_process) {
worker_thread((void*)0);
(long)getpid());
if (one_process) {
if (shutdown_pending) {
if (is_graceful) {
static int restart_num = 0;
if (debug) {
no_detach = 0;
is_graceful = 0;
return HTTP_INTERNAL_SERVER_ERROR;
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
return OK;
static int restart_num = 0;
int startup = 0;
if (restart_num++ == 0) {
if (startup) {
if (startup) {
if (ap_threads_to_start < 0) {
if (startup) {
if (startup) {
if (ap_max_requests_per_thread < 0) {
if (startup) {
return OK;
one_process = 0;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
{ NULL }