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

📄 mpm_common.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed 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 file is to store the code that MOST mpm's will need * this does not mean a function only goes into this file if every MPM needs * it.  It means that if a function is needed by more than one MPM, and * future maintenance would be served by making the code common, then the * function belongs here. * * This is going in src/main because it is not platform specific, it is * specific to multi-process servers, but NOT to Unix.  Which is why it * does not belong in src/os/unix */#include "apr.h"#include "apr_thread_proc.h"#include "apr_signal.h"#include "apr_strings.h"#define APR_WANT_STRFUNC#include "apr_want.h"#include "apr_getopt.h"#include "apr_optional.h"#include "apr_allocator.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"#ifdef AP_MPM_WANT_SET_SCOREBOARD#include "scoreboard.h"#endif#ifdef HAVE_PWD_H#include <pwd.h>#endif#ifdef HAVE_GRP_H#include <grp.h>#endif#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#ifdef AP_MPM_WANT_RECLAIM_CHILD_PROCESSESvoid ap_reclaim_child_processes(int terminate){    int i;    long int waittime = 1024 * 16;      /* in usecs */    apr_status_t waitret;    int tries;    int not_dead_yet;    int max_daemons;    ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);    for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {        /* don't want to hold up progress any more than         * necessary, but we need to allow children a few moments to exit.         * Set delay with an exponential backoff.         */        apr_sleep(waittime);        waittime = waittime * 4;        /* now see who is done */        not_dead_yet = 0;        for (i = 0; i < max_daemons; ++i) {            pid_t pid = MPM_CHILD_PID(i);            apr_proc_t proc;            if (pid == 0)                continue;            proc.pid = pid;            waitret = apr_proc_wait(&proc, NULL, NULL, APR_NOWAIT);            if (waitret != APR_CHILD_NOTDONE) {                MPM_NOTE_CHILD_KILLED(i);                continue;            }            ++not_dead_yet;            switch (tries) {            case 1:     /*  16ms */            case 2:     /*  82ms */            case 3:     /* 344ms */            case 4:     /*  16ms */                break;            case 5:     /*  82ms */            case 6:     /* 344ms */            case 7:     /* 1.4sec */                /* ok, now it's being annoying */                ap_log_error(APLOG_MARK, APLOG_WARNING,                             0, ap_server_conf,                             "child process %ld still did not exit, "                             "sending a SIGTERM",                             (long)pid);                kill(pid, SIGTERM);                break;            case 8:     /*  6 sec */                /* die child scum */                ap_log_error(APLOG_MARK, APLOG_ERR,                             0, ap_server_conf,                             "child process %ld still did not exit, "                             "sending a SIGKILL",                             (long)pid);#ifndef BEOS                kill(pid, SIGKILL);#else                /* sending a SIGKILL kills the entire team on BeOS, and as                 * httpd thread is part of that team it removes any chance                 * of ever doing a restart.  To counter this I'm changing to                 * use a kinder, gentler way of killing a specific thread                 * that is just as effective.                 */                kill_thread(pid);#endif                break;            case 9:     /* 14 sec */                /* gave it our best shot, but alas...  If this really                 * is a child we are trying to kill and it really hasn't                 * exited, we will likely fail to bind to the port                 * after the restart.                 */                ap_log_error(APLOG_MARK, APLOG_ERR,                             0, ap_server_conf,                             "could not make child process %ld exit, "                             "attempting to continue anyway",                             (long)pid);                break;            }        }#if APR_HAS_OTHER_CHILD        apr_proc_other_child_check();#endif        if (!not_dead_yet) {            /* nothing left to wait for */            break;        }    }}#endif /* AP_MPM_WANT_RECLAIM_CHILD_PROCESSES */#ifdef AP_MPM_WANT_WAIT_OR_TIMEOUT/* number of calls to wait_or_timeout between writable probes */#ifndef INTERVAL_OF_WRITABLE_PROBES#define INTERVAL_OF_WRITABLE_PROBES 10#endifstatic int wait_or_timeout_counter;void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret,                        apr_pool_t *p){    apr_status_t rv;    ++wait_or_timeout_counter;    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {        wait_or_timeout_counter = 0;    }    rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);    if (APR_STATUS_IS_EINTR(rv)) {        ret->pid = -1;        return;    }    if (APR_STATUS_IS_CHILD_DONE(rv)) {        return;    }#ifdef NEED_WAITPID    if ((ret = reap_children(exitcode, status)) > 0) {        return;    }#endif    apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);    ret->pid = -1;    return;}#endif /* AP_MPM_WANT_WAIT_OR_TIMEOUT */#ifdef AP_MPM_WANT_PROCESS_CHILD_STATUSint ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status){    int signum = status;    const char *sigdesc = apr_signal_description_get(signum);    /* Child died... if it died due to a fatal error,     * we should simply bail out.  The caller needs to     * check for bad rc from us and exit, running any     * appropriate cleanups.     *     * If the child died due to a resource shortage,      * the parent should limit the rate of forking     */    if (APR_PROC_CHECK_EXIT(why)) {        if (status == APEXIT_CHILDSICK) {            return status;        }        if (status == APEXIT_CHILDFATAL) {            ap_log_error(APLOG_MARK, APLOG_ALERT,                         0, ap_server_conf,                         "Child %" APR_PID_T_FMT                         " returned a Fatal error..." APR_EOL_STR                         "Apache is exiting!",                         pid->pid);            return APEXIT_CHILDFATAL;        }        return 0;    }    if (APR_PROC_CHECK_SIGNALED(why)) {        switch (signum) {        case SIGTERM:        case SIGHUP:        case AP_SIG_GRACEFUL:        case SIGKILL:            break;        default:            if (APR_PROC_CHECK_CORE_DUMP(why)) {                ap_log_error(APLOG_MARK, APLOG_NOTICE,                             0, ap_server_conf,                             "child pid %ld exit signal %s (%d), "                             "possible coredump in %s",                             (long)pid->pid, sigdesc, signum,                             ap_coredump_dir);            }            else {                ap_log_error(APLOG_MARK, APLOG_NOTICE,                             0, ap_server_conf,                             "child pid %ld exit signal %s (%d)",                             (long)pid->pid, sigdesc, signum);            }        }    }    return 0;}#endif /* AP_MPM_WANT_PROCESS_CHILD_STATUS */#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)void ap_sock_disable_nagle(apr_socket_t *s){    /* The Nagle algorithm says that we should delay sending partial     * packets in hopes of getting more data.  We don't want to do     * this; we are not telnet.  There are bad interactions between     * persistent connections and Nagle's algorithm that have very severe     * performance penalties.  (Failing to disable Nagle is not much of a     * problem with simple HTTP.)     *     * In spite of these problems, failure here is not a shooting offense.     */    apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);    if (status != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf,                     "apr_socket_opt_set: (TCP_NODELAY)");    }}#endif#ifdef HAVE_GETPWNAMAP_DECLARE(uid_t) ap_uname2id(const char *name){    struct passwd *ent;    if (name[0] == '#')        return (atoi(&name[1]));    if (!(ent = getpwnam(name))) {        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,                     "%s: bad user name %s", ap_server_argv0, name);        exit(1);    }    return (ent->pw_uid);}#endif#ifdef HAVE_GETGRNAMAP_DECLARE(gid_t) ap_gname2id(const char *name){    struct group *ent;    if (name[0] == '#')        return (atoi(&name[1]));    if (!(ent = getgrnam(name))) {        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,                     "%s: bad group name %s", ap_server_argv0, name);        exit(1);    }    return (ent->gr_gid);}#endif#ifndef HAVE_INITGROUPSint initgroups(const char *name, gid_t basegid){#if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF) || defined(__TANDEM) || defined(OS2) || defined(WIN32) || defined(NETWARE)/* QNX, MPE and BeOS do not appear to support supplementary groups. */    return 0;#else /* ndef QNX */    gid_t groups[NGROUPS_MAX];    struct group *g;    int index = 0;    setgrent();    groups[index++] = basegid;    while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {        if (g->gr_gid != basegid) {            char **names;            for (names = g->gr_mem; *names != NULL; ++names) {                if (!strcmp(*names, name))                    groups[index++] = g->gr_gid;            }        }    }    endgrent();    return setgroups(index, groups);#endif /* def QNX */}#endif /* def NEED_INITGROUPS */#ifdef AP_MPM_USES_PODAP_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;    apr_sockaddr_info_get(&(*pod)->sa, ap_listeners->bind_addr->hostname,                          APR_UNSPEC, ap_listeners->bind_addr->port, 0, p);    /* close these before exec. */    apr_file_unset_inherit((*pod)->pod_in);    apr_file_unset_inherit((*pod)->pod_out);    return APR_SUCCESS;}AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod){    char c;    apr_size_t len = 1;    apr_status_t rv;    rv = apr_file_read(pod->pod_in, &c, &len);    if ((rv == APR_SUCCESS) && (len == 1)) {        return APR_SUCCESS;    }    if (rv != APR_SUCCESS) {        return rv;    }    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 APR_SUCCESS;}static apr_status_t pod_signal_internal(ap_pod_t *pod){    apr_status_t rv;    char char_of_death = '!';    apr_size_t one = 1;    rv = apr_file_write(pod->pod_out, &char_of_death, &one);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,                     "write pipe_of_death");    }    return rv;}/* This function connects to the server, then immediately closes the connection. * This permits the MPM to skip the poll when there is only one listening * socket, because it provides a alternate way to unblock an accept() when * the pod is used. */static apr_status_t dummy_connection(ap_pod_t *pod){    apr_status_t rv;    apr_socket_t *sock;    apr_pool_t *p;    /* create a temporary pool for the socket.  pconf stays around too long */    rv = apr_pool_create(&p, pod->p);    if (rv != APR_SUCCESS) {        return rv;    }    rv = apr_socket_create(&sock, pod->sa->family, SOCK_STREAM, p);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,                     "get socket to connect to listener");        return rv;    }    /* on some platforms (e.g., FreeBSD), the kernel won't accept many     * queued connections before it starts blocking local connects...     * we need to keep from blocking too long and instead return an error,     * because the MPM won't want to hold up a graceful restart for a     * long time     */    rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,                     "set timeout on socket to connect to listener");        apr_socket_close(sock);        return rv;    }    rv = apr_connect(sock, pod->sa);    if (rv != APR_SUCCESS) {        int log_level = APLOG_WARNING;        if (APR_STATUS_IS_TIMEUP(rv)) {            /* probably some server processes bailed out already and there             * is nobody around to call accept and clear out the kernel             * connection queue; usually this is not worth logging             */            log_level = APLOG_DEBUG;        }        ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf,                     "connect to listener");    }    apr_socket_close(sock);    apr_pool_destroy(p);    return rv;}AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod){    apr_status_t rv;    rv = pod_signal_internal(pod);    if (rv != APR_SUCCESS) {        return rv;    }    return dummy_connection(pod);}void ap_mpm_pod_killpg(ap_pod_t *pod, int num){    int i;    apr_status_t rv = APR_SUCCESS;    /* we don't write anything to the pod here...  we assume     * that the would-be reader of the pod has another way to     * see that it is time to die once we wake it up     *     * writing lots of things to the pod at once is very     * problematic... we can fill the kernel pipe buffer and     * be blocked until somebody consumes some bytes or     * we hit a timeout...  if we hit a timeout we can't just

⌨️ 快捷键说明

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