Blame server/mpm_common.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* The purpose of this file is to store the code that MOST mpm's will need
Packit 90a5c9
 * this does not mean a function only goes into this file if every MPM needs
Packit 90a5c9
 * it.  It means that if a function is needed by more than one MPM, and
Packit 90a5c9
 * future maintenance would be served by making the code common, then the
Packit 90a5c9
 * function belongs here.
Packit 90a5c9
 *
Packit 90a5c9
 * This is going in src/main because it is not platform specific, it is
Packit 90a5c9
 * specific to multi-process servers, but NOT to Unix.  Which is why it
Packit 90a5c9
 * does not belong in src/os/unix
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "apr.h"
Packit 90a5c9
#include "apr_thread_proc.h"
Packit 90a5c9
#include "apr_signal.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#define APR_WANT_STRFUNC
Packit 90a5c9
#include "apr_want.h"
Packit 90a5c9
#include "apr_getopt.h"
Packit 90a5c9
#include "apr_optional.h"
Packit 90a5c9
#include "apr_allocator.h"
Packit 90a5c9
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "http_config.h"
Packit 90a5c9
#include "http_core.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "http_main.h"
Packit 90a5c9
#include "mpm_common.h"
Packit 90a5c9
#include "mod_core.h"
Packit 90a5c9
#include "ap_mpm.h"
Packit 90a5c9
#include "ap_listen.h"
Packit 90a5c9
#include "util_mutex.h"
Packit 90a5c9
Packit 90a5c9
#include "scoreboard.h"
Packit 90a5c9
Packit 90a5c9
#ifdef HAVE_PWD_H
Packit 90a5c9
#include <pwd.h>
Packit 90a5c9
#endif
Packit 90a5c9
#ifdef HAVE_GRP_H
Packit 90a5c9
#include <grp.h>
Packit 90a5c9
#endif
Packit 90a5c9
#if APR_HAVE_UNISTD_H
Packit 90a5c9
#include <unistd.h>
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/* we know core's module_index is 0 */
Packit 90a5c9
#undef APLOG_MODULE_INDEX
Packit 90a5c9
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
Packit 90a5c9
Packit 90a5c9
#define DEFAULT_HOOK_LINKS \
Packit 90a5c9
    APR_HOOK_LINK(monitor) \
Packit 90a5c9
    APR_HOOK_LINK(drop_privileges) \
Packit 90a5c9
    APR_HOOK_LINK(mpm) \
Packit 90a5c9
    APR_HOOK_LINK(mpm_query) \
Packit 90a5c9
    APR_HOOK_LINK(mpm_register_timed_callback) \
Packit 90a5c9
    APR_HOOK_LINK(mpm_get_name) \
Packit 90a5c9
    APR_HOOK_LINK(end_generation) \
Packit 90a5c9
    APR_HOOK_LINK(child_status) \
Packit 90a5c9
    APR_HOOK_LINK(suspend_connection) \
Packit 90a5c9
    APR_HOOK_LINK(resume_connection)
Packit 90a5c9
Packit 90a5c9
#if AP_ENABLE_EXCEPTION_HOOK
Packit 90a5c9
APR_HOOK_STRUCT(
Packit 90a5c9
    APR_HOOK_LINK(fatal_exception)
Packit 90a5c9
    DEFAULT_HOOK_LINKS
Packit 90a5c9
)
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
Packit 90a5c9
                          (ap_exception_info_t *ei), (ei), OK, DECLINED)
Packit 90a5c9
#else
Packit 90a5c9
APR_HOOK_STRUCT(
Packit 90a5c9
    DEFAULT_HOOK_LINKS
Packit 90a5c9
)
Packit 90a5c9
#endif
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
Packit 90a5c9
                          (apr_pool_t *p, server_rec *s), (p, s), OK, DECLINED)
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_ALL(int, drop_privileges,
Packit 90a5c9
                          (apr_pool_t * pchild, server_rec * s),
Packit 90a5c9
                          (pchild, s), OK, DECLINED)
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm,
Packit 90a5c9
                            (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
Packit 90a5c9
                            (pconf, plog, s), DECLINED)
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm_query,
Packit 90a5c9
                            (int query_code, int *result, apr_status_t *_rv),
Packit 90a5c9
                            (query_code, result, _rv), DECLINED)
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
Packit 90a5c9
                            (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton),
Packit 90a5c9
                            (t, cbfn, baton), APR_ENOTIMPL)
Packit 90a5c9
AP_IMPLEMENT_HOOK_VOID(end_generation,
Packit 90a5c9
                       (server_rec *s, ap_generation_t gen),
Packit 90a5c9
                       (s, gen))
Packit 90a5c9
AP_IMPLEMENT_HOOK_VOID(child_status,
Packit 90a5c9
                       (server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status status),
Packit 90a5c9
                       (s,pid,gen,slot,status))
Packit 90a5c9
AP_IMPLEMENT_HOOK_VOID(suspend_connection,
Packit 90a5c9
                       (conn_rec *c, request_rec *r),
Packit 90a5c9
                       (c, r))
Packit 90a5c9
AP_IMPLEMENT_HOOK_VOID(resume_connection,
Packit 90a5c9
                       (conn_rec *c, request_rec *r),
Packit 90a5c9
                       (c, r))
Packit 90a5c9
Packit 90a5c9
/* hooks with no args are implemented last, after disabling APR hook probes */
Packit 90a5c9
#if defined(APR_HOOK_PROBES_ENABLED)
Packit 90a5c9
#undef APR_HOOK_PROBES_ENABLED
Packit 90a5c9
#undef APR_HOOK_PROBE_ENTRY
Packit 90a5c9
#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args)
Packit 90a5c9
#undef APR_HOOK_PROBE_RETURN
Packit 90a5c9
#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
Packit 90a5c9
#undef APR_HOOK_PROBE_INVOKE
Packit 90a5c9
#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args)
Packit 90a5c9
#undef APR_HOOK_PROBE_COMPLETE
Packit 90a5c9
#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args)
Packit 90a5c9
#undef APR_HOOK_INT_DCL_UD
Packit 90a5c9
#define APR_HOOK_INT_DCL_UD
Packit 90a5c9
#endif
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
Packit 90a5c9
                            (void),
Packit 90a5c9
                            (), NULL)
Packit 90a5c9
Packit 90a5c9
typedef struct mpm_gen_info_t {
Packit 90a5c9
    APR_RING_ENTRY(mpm_gen_info_t) link;
Packit 90a5c9
    int gen;          /* which gen? */
Packit 90a5c9
    int active;       /* number of active processes */
Packit 90a5c9
    int done;         /* gen finished? (whether or not active processes) */
Packit 90a5c9
} mpm_gen_info_t;
Packit 90a5c9
Packit 90a5c9
APR_RING_HEAD(mpm_gen_info_head_t, mpm_gen_info_t);
Packit 90a5c9
static struct mpm_gen_info_head_t *geninfo, *unused_geninfo;
Packit 90a5c9
static int gen_head_init; /* yuck */
Packit 90a5c9
Packit 90a5c9
/* variables representing config directives implemented here */
Packit 90a5c9
AP_DECLARE_DATA const char *ap_pid_fname;
Packit 90a5c9
AP_DECLARE_DATA int ap_max_requests_per_child;
Packit 90a5c9
AP_DECLARE_DATA char ap_coredump_dir[MAX_STRING_LEN];
Packit 90a5c9
AP_DECLARE_DATA int ap_coredumpdir_configured;
Packit 90a5c9
AP_DECLARE_DATA int ap_graceful_shutdown_timeout;
Packit 90a5c9
AP_DECLARE_DATA apr_uint32_t ap_max_mem_free;
Packit 90a5c9
AP_DECLARE_DATA apr_size_t ap_thread_stacksize;
Packit 90a5c9
Packit 90a5c9
#define ALLOCATOR_MAX_FREE_DEFAULT (2048*1024)
Packit 90a5c9
Packit 90a5c9
/* Set defaults for config directives implemented here.  This is
Packit 90a5c9
 * called from core's pre-config hook, so MPMs which need to override
Packit 90a5c9
 * one of these should run their pre-config hook after that of core.
Packit 90a5c9
 */
Packit 90a5c9
void mpm_common_pre_config(apr_pool_t *pconf)
Packit 90a5c9
{
Packit 90a5c9
    ap_pid_fname = DEFAULT_PIDLOG;
Packit 90a5c9
    ap_max_requests_per_child = 0; /* unlimited */
Packit 90a5c9
    apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
Packit 90a5c9
    ap_coredumpdir_configured = 0;
Packit 90a5c9
    ap_graceful_shutdown_timeout = 0; /* unlimited */
Packit 90a5c9
    ap_max_mem_free = ALLOCATOR_MAX_FREE_DEFAULT;
Packit 90a5c9
    ap_thread_stacksize = 0; /* use system default */
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* number of calls to wait_or_timeout between writable probes */
Packit 90a5c9
#ifndef INTERVAL_OF_WRITABLE_PROBES
Packit 90a5c9
#define INTERVAL_OF_WRITABLE_PROBES 10
Packit 90a5c9
#endif
Packit 90a5c9
static int wait_or_timeout_counter;
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode,
Packit 90a5c9
                                    apr_proc_t *ret, apr_pool_t *p,
Packit 90a5c9
                                    server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    ++wait_or_timeout_counter;
Packit 90a5c9
    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
Packit 90a5c9
        wait_or_timeout_counter = 0;
Packit 90a5c9
        ap_run_monitor(p, s);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
Packit 90a5c9
    ap_update_global_status();
Packit 90a5c9
Packit 90a5c9
    if (APR_STATUS_IS_EINTR(rv)) {
Packit 90a5c9
        ret->pid = -1;
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (APR_STATUS_IS_CHILD_DONE(rv)) {
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    apr_sleep(apr_time_from_sec(1));
Packit 90a5c9
    ret->pid = -1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#if defined(TCP_NODELAY)
Packit 90a5c9
void ap_sock_disable_nagle(apr_socket_t *s)
Packit 90a5c9
{
Packit 90a5c9
    /* The Nagle algorithm says that we should delay sending partial
Packit 90a5c9
     * packets in hopes of getting more data.  We don't want to do
Packit 90a5c9
     * this; we are not telnet.  There are bad interactions between
Packit 90a5c9
     * persistent connections and Nagle's algorithm that have very severe
Packit 90a5c9
     * performance penalties.  (Failing to disable Nagle is not much of a
Packit 90a5c9
     * problem with simple HTTP.)
Packit 90a5c9
     *
Packit 90a5c9
     * In spite of these problems, failure here is not a shooting offense.
Packit 90a5c9
     */
Packit 90a5c9
    apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
Packit 90a5c9
Packit 90a5c9
    if (status != APR_SUCCESS) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf, APLOGNO(00542)
Packit 90a5c9
                     "apr_socket_opt_set: (TCP_NODELAY)");
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifdef HAVE_GETPWNAM
Packit 90a5c9
AP_DECLARE(uid_t) ap_uname2id(const char *name)
Packit 90a5c9
{
Packit 90a5c9
    struct passwd *ent;
Packit 90a5c9
Packit 90a5c9
    if (name[0] == '#')
Packit 90a5c9
        return (atoi(&name[1]));
Packit 90a5c9
Packit 90a5c9
    if (!(ent = getpwnam(name))) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00543)
Packit 90a5c9
                     "%s: bad user name %s", ap_server_argv0, name);
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return (ent->pw_uid);
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifdef HAVE_GETGRNAM
Packit 90a5c9
AP_DECLARE(gid_t) ap_gname2id(const char *name)
Packit 90a5c9
{
Packit 90a5c9
    struct group *ent;
Packit 90a5c9
Packit 90a5c9
    if (name[0] == '#')
Packit 90a5c9
        return (atoi(&name[1]));
Packit 90a5c9
Packit 90a5c9
    if (!(ent = getgrnam(name))) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00544)
Packit 90a5c9
                     "%s: bad group name %s", ap_server_argv0, name);
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return (ent->gr_gid);
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifndef HAVE_INITGROUPS
Packit 90a5c9
int initgroups(const char *name, gid_t basegid)
Packit 90a5c9
{
Packit 90a5c9
#if defined(_OSD_POSIX) || defined(OS2) || defined(WIN32) || defined(NETWARE)
Packit 90a5c9
    return 0;
Packit 90a5c9
#else
Packit 90a5c9
    gid_t groups[NGROUPS_MAX];
Packit 90a5c9
    struct group *g;
Packit 90a5c9
    int index = 0;
Packit 90a5c9
Packit 90a5c9
    setgrent();
Packit 90a5c9
Packit 90a5c9
    groups[index++] = basegid;
Packit 90a5c9
Packit 90a5c9
    while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {
Packit 90a5c9
        if (g->gr_gid != basegid) {
Packit 90a5c9
            char **names;
Packit 90a5c9
Packit 90a5c9
            for (names = g->gr_mem; *names != NULL; ++names) {
Packit 90a5c9
                if (!strcmp(*names, name))
Packit 90a5c9
                    groups[index++] = g->gr_gid;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    endgrent();
Packit 90a5c9
Packit 90a5c9
    return setgroups(index, groups);
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
#endif /* def HAVE_INITGROUPS */
Packit 90a5c9
Packit 90a5c9
/* standard mpm configuration handling */
Packit 90a5c9
Packit 90a5c9
const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                               const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (cmd->server->is_virtual) {
Packit 90a5c9
        return "PidFile directive not allowed in <VirtualHost>";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ap_pid_fname = arg;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void ap_mpm_dump_pidfile(apr_pool_t *p, apr_file_t *out)
Packit 90a5c9
{
Packit 90a5c9
    apr_file_printf(out, "PidFile: \"%s\"\n",
Packit 90a5c9
                    ap_server_root_relative(p, ap_pid_fname));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                                    const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!strcasecmp(cmd->cmd->name, "MaxRequestsPerChild")) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(00545)
Packit 90a5c9
                     "MaxRequestsPerChild is deprecated, use "
Packit 90a5c9
                     "MaxConnectionsPerChild instead.");
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ap_max_requests_per_child = atoi(arg);
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                                   const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_finfo_t finfo;
Packit 90a5c9
    const char *fname;
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    fname = ap_server_root_relative(cmd->temp_pool, arg);
Packit 90a5c9
    if (!fname) {
Packit 90a5c9
        return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ",
Packit 90a5c9
                           arg, NULL);
Packit 90a5c9
    }
Packit 90a5c9
    if (apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) {
Packit 90a5c9
        return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
Packit 90a5c9
                           " does not exist", NULL);
Packit 90a5c9
    }
Packit 90a5c9
    if (finfo.filetype != APR_DIR) {
Packit 90a5c9
        return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
Packit 90a5c9
                           " is not a directory", NULL);
Packit 90a5c9
    }
Packit 90a5c9
    apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
Packit 90a5c9
    ap_coredumpdir_configured = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *)ap_mpm_set_graceful_shutdown(cmd_parms *cmd,
Packit 90a5c9
                                                     void *dummy,
Packit 90a5c9
                                                     const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
    ap_graceful_shutdown_timeout = atoi(arg);
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                                    const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    long value;
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    errno = 0;
Packit 90a5c9
    value = strtol(arg, NULL, 10);
Packit 90a5c9
    if (value < 0 || errno == ERANGE)
Packit 90a5c9
        return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ",
Packit 90a5c9
                           arg, NULL);
Packit 90a5c9
Packit 90a5c9
    ap_max_mem_free = (apr_uint32_t)value * 1024;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                                        const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    long value;
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    errno = 0;
Packit 90a5c9
    value = strtol(arg, NULL, 10);
Packit 90a5c9
    if (value < 0 || errno == ERANGE)
Packit 90a5c9
        return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ",
Packit 90a5c9
                           arg, NULL);
Packit 90a5c9
Packit 90a5c9
    ap_thread_stacksize = (apr_size_t)value;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    if (ap_run_mpm_query(query_code, result, &rv) == DECLINED) {
Packit 90a5c9
        rv = APR_EGENERAL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void end_gen(mpm_gen_info_t *gi)
Packit 90a5c9
{
Packit 90a5c9
    ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
Packit 90a5c9
                 "end of generation %d", gi->gen);
Packit 90a5c9
    ap_run_end_generation(ap_server_conf, gi->gen);
Packit 90a5c9
    APR_RING_REMOVE(gi, link);
Packit 90a5c9
    APR_RING_INSERT_HEAD(unused_geninfo, gi, mpm_gen_info_t, link);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t ap_mpm_end_gen_helper(void *unused) /* cleanup on pconf */
Packit 90a5c9
{
Packit 90a5c9
    int gen = ap_config_generation - 1; /* differs from MPM generation */
Packit 90a5c9
    mpm_gen_info_t *cur;
Packit 90a5c9
Packit 90a5c9
    if (geninfo == NULL) {
Packit 90a5c9
        /* initial pconf teardown, MPM hasn't run */
Packit 90a5c9
        return APR_SUCCESS;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    cur = APR_RING_FIRST(geninfo);
Packit 90a5c9
    while (cur != APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link) &&
Packit 90a5c9
           cur->gen != gen) {
Packit 90a5c9
        cur = APR_RING_NEXT(cur, link);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
Packit 90a5c9
        /* last child of generation already exited */
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
Packit 90a5c9
                     "no record of generation %d", gen);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        cur->done = 1;
Packit 90a5c9
        if (cur->active == 0) {
Packit 90a5c9
            end_gen(cur);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* core's child-status hook
Packit 90a5c9
 * tracks number of remaining children per generation and
Packit 90a5c9
 * runs the end-generation hook when the last child of
Packit 90a5c9
 * a generation exits
Packit 90a5c9
 */
Packit 90a5c9
void ap_core_child_status(server_rec *s, pid_t pid,
Packit 90a5c9
                          ap_generation_t gen, int slot,
Packit 90a5c9
                          mpm_child_status status)
Packit 90a5c9
{
Packit 90a5c9
    mpm_gen_info_t *cur;
Packit 90a5c9
    const char *status_msg = "unknown status";
Packit 90a5c9
Packit 90a5c9
    if (!gen_head_init) { /* where to run this? */
Packit 90a5c9
        gen_head_init = 1;
Packit 90a5c9
        geninfo = apr_pcalloc(s->process->pool, sizeof *geninfo);
Packit 90a5c9
        unused_geninfo = apr_pcalloc(s->process->pool, sizeof *unused_geninfo);
Packit 90a5c9
        APR_RING_INIT(geninfo, mpm_gen_info_t, link);
Packit 90a5c9
        APR_RING_INIT(unused_geninfo, mpm_gen_info_t, link);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    cur = APR_RING_FIRST(geninfo);
Packit 90a5c9
    while (cur != APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link) &&
Packit 90a5c9
           cur->gen != gen) {
Packit 90a5c9
        cur = APR_RING_NEXT(cur, link);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    switch(status) {
Packit 90a5c9
    case MPM_CHILD_STARTED:
Packit 90a5c9
        status_msg = "started";
Packit 90a5c9
        if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
Packit 90a5c9
            /* first child for this generation */
Packit 90a5c9
            if (!APR_RING_EMPTY(unused_geninfo, mpm_gen_info_t, link)) {
Packit 90a5c9
                cur = APR_RING_FIRST(unused_geninfo);
Packit 90a5c9
                APR_RING_REMOVE(cur, link);
Packit 90a5c9
                cur->active = cur->done = 0;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                cur = apr_pcalloc(s->process->pool, sizeof *cur);
Packit 90a5c9
            }
Packit 90a5c9
            cur->gen = gen;
Packit 90a5c9
            APR_RING_ELEM_INIT(cur, link);
Packit 90a5c9
            APR_RING_INSERT_HEAD(geninfo, cur, mpm_gen_info_t, link);
Packit 90a5c9
        }
Packit 90a5c9
        ap_random_parent_after_fork();
Packit 90a5c9
        ++cur->active;
Packit 90a5c9
        break;
Packit 90a5c9
    case MPM_CHILD_EXITED:
Packit 90a5c9
        ap_update_global_status();
Packit 90a5c9
        status_msg = "exited";
Packit 90a5c9
        if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00546)
Packit 90a5c9
                         "no record of generation %d of exiting child %" APR_PID_T_FMT,
Packit 90a5c9
                         gen, pid);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            --cur->active;
Packit 90a5c9
            if (!cur->active && cur->done) { /* no children, server has stopped/restarted */
Packit 90a5c9
                end_gen(cur);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    case MPM_CHILD_LOST_SLOT:
Packit 90a5c9
        status_msg = "lost slot";
Packit 90a5c9
        /* we don't track by slot, so it doesn't matter */
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
    ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, s,
Packit 90a5c9
                 "mpm child %" APR_PID_T_FMT " (gen %d/slot %d) %s",
Packit 90a5c9
                 pid, gen, slot, status_msg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton)
Packit 90a5c9
{
Packit 90a5c9
    return ap_run_mpm_register_timed_callback(t, cbfn, baton);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *)ap_show_mpm(void)
Packit 90a5c9
{
Packit 90a5c9
    const char *name = ap_run_mpm_get_name();
Packit 90a5c9
Packit 90a5c9
    if (!name) {
Packit 90a5c9
        name = "";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return name;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *)ap_check_mpm(void)
Packit 90a5c9
{
Packit 90a5c9
    static const char *last_mpm_name = NULL;
Packit 90a5c9
Packit 90a5c9
    if (!_hooks.link_mpm || _hooks.link_mpm->nelts == 0)
Packit 90a5c9
        return "No MPM loaded.";
Packit 90a5c9
    else if (_hooks.link_mpm->nelts > 1)
Packit 90a5c9
        return "More than one MPM loaded.";
Packit 90a5c9
Packit 90a5c9
    if (last_mpm_name) {
Packit 90a5c9
        if (strcmp(last_mpm_name, ap_show_mpm())) {
Packit 90a5c9
            return "The MPM cannot be changed during restart.";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        last_mpm_name = apr_pstrdup(ap_pglobal, ap_show_mpm());
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}