⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 beos.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 BeOS MPM! * * This is a single process, with multiple worker threads. * * Under testing I found that given the inability of BeOS to handle threads * and forks it didn't make sense to try and have a set of "children" threads * that spawned the "worker" threads, so just missed out the middle mand and * somehow arrived here. * * For 2.1 this has been rewritten to have simpler logic, though there is still * some simplification that can be done. It's still a work in progress! * * TODO Items * * - on exit most worker threads segfault trying to access a kernel page. */#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 int mpm_state = AP_MPMQ_STARTING;apr_thread_mutex_t *accept_mutex = NULL;static apr_pool_t *pconf;    /* Pool for config stuff */static int server_pid;/* * 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;server_rec *ap_server_conf;/* one_process */static int one_process = 0;#ifdef DEBUG_SIGSTOPint raise_sigstop_flags;#endifstatic void check_restart(void *data);/* When a worker thread gets to the end of it's life it dies with an * exit value of the code supplied to this function. The thread has * already had check_restart() registered to be called when dying, so * we don't concern ourselves with restarting at all here. We do however * mark the scoreboard slot as belonging to a dead server and zero out * it's thread_id. * * TODO - use the status we set to determine if we need to restart the *        thread. */static void clean_child_exit(int code, int slot){    (void) ap_update_child_status_from_indexes(0, slot, SERVER_DEAD,                                               (request_rec*)NULL);    ap_scoreboard_image->servers[0][slot].tid = 0;    exit_thread(code);}/***************************************************************** * 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){    /* If the user tries to shut us down twice in quick succession then we     * may well get triggered while we are working through previous attempt     * to shutdown. We won't worry about even reporting it as it seems a little     * pointless.     */    if (shutdown_pending == 1)        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;}/* sig_coredump attempts to handle all the potential signals we * may get that should result in a core dump. This is called from * the signal handler routine, so when we enter we are essentially blocked * on the signal. Once we exit we will allow the signal to be processed by * system, which may or may not produce a .core file. All this function does * is try and respect the users wishes about where that file should be * located (chdir) and then signal the parent with the signal. * * If we called abort() the parent would only see SIGABRT which doesn't provide * as much information. */static void sig_coredump(int sig){    chdir(ap_coredump_dir);    signal(sig, SIG_DFL);    kill(server_pid, sig);}static void sig_term(int sig){    ap_start_shutdown();}static void restart(int sig){    ap_start_restart(sig == AP_SIG_GRACEFUL);}/* Handle queries about our inner workings... */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;}/* This accepts a connection and allows us to handle the error codes better than * the previous code, while also making it more obvious. */static apr_status_t beos_accept(void **accepted, ap_listen_rec *lr, apr_pool_t *ptrans){    apr_socket_t *csd;    apr_status_t status;    int sockdes;    *accepted = NULL;    status = apr_socket_accept(&csd, lr->sd, ptrans);    if (status == APR_SUCCESS) {        *accepted = csd;        apr_os_sock_get(&sockdes, csd);        return status;    }    if (APR_STATUS_IS_EINTR(status)) {        return status;    }        /* This switch statement provides us with better error details. */    switch (status) {#ifdef ECONNABORTED        case ECONNABORTED:#endif#ifdef ETIMEDOUT        case ETIMEDOUT:#endif#ifdef EHOSTUNREACH        case EHOSTUNREACH:#endif#ifdef ENETUNREACH        case ENETUNREACH:#endif            break;#ifdef ENETDOWN        case ENETDOWN:            /*             * 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, status, ap_server_conf,                         "apr_socket_accept: giving up.");            return APR_EGENERAL;#endif /*ENETDOWN*/        default:            ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,                         "apr_socket_accept: (client socket)");            return APR_EGENERAL;    }    return status;}static void tell_workers_to_exit(void){    apr_size_t len;    int i = 0;    for (i = 0 ; i < ap_max_child_assigned; i++){        len = 4;        if (apr_socket_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;    /* The first batch get handled by sig_coredump */    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;    }    /* These next two are handled by sig_term */    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)");    /* We ignore 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)");    /* 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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -