prefork.c revision 20e0c71be778348516719e1e58a9f55c8e78c570
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * http://www.apache.org/licenses/LICENSE-2.0
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * Unless required by applicable law or agreed to in writing, software
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * distributed under the License is distributed on an "AS IS" BASIS,
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * See the License for the specific language governing permissions and
04891cf70e0bfc38bfb027541dc821f04c754ff7nd * limitations under the License.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr_portable.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr_strings.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr_thread_proc.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr_signal.h"
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#define APR_WANT_STDIO
3568de757bac0b47256647504c186d17ca272f85rbb#define APR_WANT_STRFUNC
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr_want.h"
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#if APR_HAVE_UNISTD_H
3568de757bac0b47256647504c186d17ca272f85rbb#include <unistd.h>
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb#if APR_HAVE_SYS_TYPES_H
3568de757bac0b47256647504c186d17ca272f85rbb#include <sys/types.h>
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#include "ap_config.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "httpd.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "mpm_default.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "http_main.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "http_log.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "http_config.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "http_core.h" /* for get_remote_host */
3568de757bac0b47256647504c186d17ca272f85rbb#include "http_connection.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "scoreboard.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "ap_mpm.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "util_mutex.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "unixd.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "mpm_common.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "ap_listen.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "ap_mmn.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "apr_poll.h"
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef HAVE_TIME_H
3568de757bac0b47256647504c186d17ca272f85rbb#include <time.h>
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef HAVE_SYS_PROCESSOR_H
3568de757bac0b47256647504c186d17ca272f85rbb#include <sys/processor.h> /* for bindprocessor() */
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include <signal.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include <sys/times.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* Limit on the total --- clients will be locked out if more servers than
3568de757bac0b47256647504c186d17ca272f85rbb * this are needed. It is intended solely to keep the server from crashing
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick * when things get out of hand.
3568de757bac0b47256647504c186d17ca272f85rbb *
3568de757bac0b47256647504c186d17ca272f85rbb * We keep a hard maximum number of servers, for two reasons --- first off,
3568de757bac0b47256647504c186d17ca272f85rbb * in case something goes seriously wrong, we want to stop the fork bomb
3568de757bac0b47256647504c186d17ca272f85rbb * short of actually crashing the machine we're running on by filling some
98fb535f829e2a95aabd82420931f476661fa8e3jorton * kernel table. Secondly, it keeps the size of the scoreboard file small
db12cd62083041bf90945eeb90cc40fbd2340797trawick * enough that we can read the whole thing without worrying too much about
db12cd62083041bf90945eeb90cc40fbd2340797trawick * the overhead.
db12cd62083041bf90945eeb90cc40fbd2340797trawick */
333eac96e4fb7d6901cb75e6ca7bb22b2ccb84cetrawick#ifndef DEFAULT_SERVER_LIMIT
333eac96e4fb7d6901cb75e6ca7bb22b2ccb84cetrawick#define DEFAULT_SERVER_LIMIT 256
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem#endif
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
3568de757bac0b47256647504c186d17ca272f85rbb * some sort of compile-time limit to help catch typos.
3568de757bac0b47256647504c186d17ca272f85rbb */
3568de757bac0b47256647504c186d17ca272f85rbb#ifndef MAX_SERVER_LIMIT
3568de757bac0b47256647504c186d17ca272f85rbb#define MAX_SERVER_LIMIT 200000
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#ifndef HARD_THREAD_LIMIT
3568de757bac0b47256647504c186d17ca272f85rbb#define HARD_THREAD_LIMIT 1
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb/* config globals */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbbstatic apr_proc_mutex_t *accept_mutex;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic int ap_daemons_to_start=0;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic int ap_daemons_min_free=0;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic int ap_daemons_max_free=0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int ap_daemons_limit=0; /* MaxClients */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic int server_limit = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int mpm_state = AP_MPMQ_STARTING;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic ap_pod_t *pod;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
8f3ec4772d2aeb347cf40e87c77627bb784dd018rbb/* data retained by prefork across load/unload of the module
8f3ec4772d2aeb347cf40e87c77627bb784dd018rbb * allocated on first call to pre-config hook; located on
3d96ee83babeec32482c9082c9426340cee8c44dwrowe * subsequent calls to pre-config hook
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
b6e310e482c42cc323a28fa6fec653e11e0552e5jortontypedef struct prefork_retained_data {
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick int first_server_limit;
98fb535f829e2a95aabd82420931f476661fa8e3jorton int module_loads;
f0e395a55abfcad3d2bd7c63470003b08a93d567nd ap_generation_t my_generation;
f0e395a55abfcad3d2bd7c63470003b08a93d567nd int volatile is_graceful; /* set from signal handler */
f0e395a55abfcad3d2bd7c63470003b08a93d567nd int maxclients_reported;
f0e395a55abfcad3d2bd7c63470003b08a93d567nd /*
98fb535f829e2a95aabd82420931f476661fa8e3jorton * The max child slot ever assigned, preserved across restarts. Necessary
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * use this value to optimize routines that have to scan the entire scoreboard.
7cd5419264796cfeaf8215383cf0f89130a81fectrawick */
7cd5419264796cfeaf8215383cf0f89130a81fectrawick int max_daemons_limit;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick /*
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * idle_spawn_rate is the number of children that will be spawned on the
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * next maintenance cycle if there aren't enough idle servers. It is
7cd5419264796cfeaf8215383cf0f89130a81fectrawick * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
3568de757bac0b47256647504c186d17ca272f85rbb * without the need to spawn.
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz */
3568de757bac0b47256647504c186d17ca272f85rbb int idle_spawn_rate;
3568de757bac0b47256647504c186d17ca272f85rbb#ifndef MAX_SPAWN_RATE
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#define MAX_SPAWN_RATE (32)
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb int hold_off_on_exponential_spawning;
3568de757bac0b47256647504c186d17ca272f85rbb} prefork_retained_data;
3568de757bac0b47256647504c186d17ca272f85rbbstatic prefork_retained_data *retained;
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb/* one_process --- debugging mode variable; can be set from the command line
3568de757bac0b47256647504c186d17ca272f85rbb * with the -X flag. If set, this gets you the child_main loop running
936a4025e45887d9f366bf54360c51937b6bcacejim * in the process which originally started up (no detach, no make_child),
936a4025e45887d9f366bf54360c51937b6bcacejim * which is a pretty nice debugging environment. (You'll get a SIGHUP
936a4025e45887d9f366bf54360c51937b6bcacejim * early in standalone_main; just continue through. This is the server
936a4025e45887d9f366bf54360c51937b6bcacejim * trying to kill off any child processes which it might have lying
936a4025e45887d9f366bf54360c51937b6bcacejim * around --- Apache doesn't keep track of their pids, it just sends
936a4025e45887d9f366bf54360c51937b6bcacejim * SIGHUP to the process group, ignoring it in the root process.
936a4025e45887d9f366bf54360c51937b6bcacejim * Continue through and you'll be fine.).
936a4025e45887d9f366bf54360c51937b6bcacejim */
936a4025e45887d9f366bf54360c51937b6bcacejim
936a4025e45887d9f366bf54360c51937b6bcacejimstatic int one_process = 0;
936a4025e45887d9f366bf54360c51937b6bcacejim
3568de757bac0b47256647504c186d17ca272f85rbbstatic apr_pool_t *pconf; /* Pool for config stuff */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbbstatic pid_t ap_my_pid; /* it seems silly to call getpid all the time */
936a4025e45887d9f366bf54360c51937b6bcacejimstatic pid_t parent_pid;
936a4025e45887d9f366bf54360c51937b6bcacejimstatic int my_child_num;
936a4025e45887d9f366bf54360c51937b6bcacejim
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef GPROF
3568de757bac0b47256647504c186d17ca272f85rbb/*
3568de757bac0b47256647504c186d17ca272f85rbb * change directory for gprof to plop the gmon.out file
3568de757bac0b47256647504c186d17ca272f85rbb * configure in httpd.conf:
41634f717c623556a16b27b25d7d909a66fe20f8wrowe * GprofDir $RuntimeDir/ -> $ServerRoot/$RuntimeDir/gmon.out
3568de757bac0b47256647504c186d17ca272f85rbb * GprofDir $RuntimeDir/% -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out
3568de757bac0b47256647504c186d17ca272f85rbb */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic void chdir_for_gprof(void)
3568de757bac0b47256647504c186d17ca272f85rbb{
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz core_server_config *sconf =
3568de757bac0b47256647504c186d17ca272f85rbb ap_get_module_config(ap_server_conf->module_config, &core_module);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz char *dir = sconf->gprof_dir;
3568de757bac0b47256647504c186d17ca272f85rbb const char *use_dir;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbb if(dir) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_status_t res;
41634f717c623556a16b27b25d7d909a66fe20f8wrowe char *buf = NULL ;
3568de757bac0b47256647504c186d17ca272f85rbb int len = strlen(sconf->gprof_dir) - 1;
3568de757bac0b47256647504c186d17ca272f85rbb if(*(dir + len) == '%') {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz dir[len] = '\0';
3568de757bac0b47256647504c186d17ca272f85rbb buf = ap_append_pid(pconf, dir, "gprof.");
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
3568de757bac0b47256647504c186d17ca272f85rbb use_dir = ap_server_root_relative(pconf, buf ? buf : dir);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz res = apr_dir_make(use_dir,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_UREAD | APR_UWRITE | APR_UEXECUTE |
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_GREAD | APR_GEXECUTE |
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz APR_WREAD | APR_WEXECUTE, pconf);
3568de757bac0b47256647504c186d17ca272f85rbb if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) {
fc1efab92032301e317f07e1b3a00082d9d71f3frbb ap_log_error(APLOG_MARK, APLOG_ERR, res, ap_server_conf,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "gprof: error creating directory %s", dir);
24b534291150023e6b68eca89ddd33e475ccddc0wrowe }
3568de757bac0b47256647504c186d17ca272f85rbb }
24b534291150023e6b68eca89ddd33e475ccddc0wrowe else {
3568de757bac0b47256647504c186d17ca272f85rbb use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR);
24b534291150023e6b68eca89ddd33e475ccddc0wrowe }
24b534291150023e6b68eca89ddd33e475ccddc0wrowe
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz chdir(use_dir);
3568de757bac0b47256647504c186d17ca272f85rbb}
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#else
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#define chdir_for_gprof()
3568de757bac0b47256647504c186d17ca272f85rbb#endif
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz/* a clean exit from a child with proper cleanup */
3568de757bac0b47256647504c186d17ca272f85rbbstatic void clean_child_exit(int code) __attribute__ ((noreturn));
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic void clean_child_exit(int code)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz{
3568de757bac0b47256647504c186d17ca272f85rbb mpm_state = AP_MPMQ_STOPPING;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbb if (pchild) {
3568de757bac0b47256647504c186d17ca272f85rbb apr_pool_destroy(pchild);
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb ap_mpm_pod_close(pod);
3568de757bac0b47256647504c186d17ca272f85rbb chdir_for_gprof();
3568de757bac0b47256647504c186d17ca272f85rbb exit(code);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz}
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic void accept_mutex_on(void)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz{
3568de757bac0b47256647504c186d17ca272f85rbb apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
3568de757bac0b47256647504c186d17ca272f85rbb if (rv != APR_SUCCESS) {
3568de757bac0b47256647504c186d17ca272f85rbb const char *msg = "couldn't grab the accept mutex";
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb if (retained->my_generation !=
3568de757bac0b47256647504c186d17ca272f85rbb ap_scoreboard_image->global->running_generation) {
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, "%s", msg);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz clean_child_exit(0);
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb else {
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "%s", msg);
3568de757bac0b47256647504c186d17ca272f85rbb exit(APEXIT_CHILDFATAL);
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb}
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbbstatic void accept_mutex_off(void)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
3568de757bac0b47256647504c186d17ca272f85rbb if (rv != APR_SUCCESS) {
239f998fbee5ac5b114b965bb76e217cce0003edstoddard const char *msg = "couldn't release the accept mutex";
78ae889ffe0fdfab72f56c6993b0f302cb48da55rbb
3568de757bac0b47256647504c186d17ca272f85rbb if (retained->my_generation !=
6653a33e820463abd4f81915b7a1eba0f602e200brianp ap_scoreboard_image->global->running_generation) {
6653a33e820463abd4f81915b7a1eba0f602e200brianp ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, "%s", msg);
6653a33e820463abd4f81915b7a1eba0f602e200brianp /* don't exit here... we have a connection to
41634f717c623556a16b27b25d7d909a66fe20f8wrowe * process, after which point we'll see that the
41634f717c623556a16b27b25d7d909a66fe20f8wrowe * generation changed and we'll exit cleanly
6653a33e820463abd4f81915b7a1eba0f602e200brianp */
3568de757bac0b47256647504c186d17ca272f85rbb }
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard else {
6653a33e820463abd4f81915b7a1eba0f602e200brianp ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "%s", msg);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick exit(APEXIT_CHILDFATAL);
3568de757bac0b47256647504c186d17ca272f85rbb }
6653a33e820463abd4f81915b7a1eba0f602e200brianp }
6653a33e820463abd4f81915b7a1eba0f602e200brianp}
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm/* On some architectures it's safe to do unserialized accept()s in the single
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick * Listen case. But it's never safe to do it in the case where there's
36c8049de63c446926139936c3d195330a0539cetrawick * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
3568de757bac0b47256647504c186d17ca272f85rbb * when it's safe in the single Listen case.
36c8049de63c446926139936c3d195330a0539cetrawick */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
e8f95a682820a599fe41b22977010636be5c2717jim#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#else
ca53a74f4012a45cbad48e940eddf27d866981f9dougm#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
ca53a74f4012a45cbad48e940eddf27d866981f9dougm#endif
ca53a74f4012a45cbad48e940eddf27d866981f9dougm
6653a33e820463abd4f81915b7a1eba0f602e200brianpstatic int prefork_query(int query_code, int *result, apr_status_t *rv)
6653a33e820463abd4f81915b7a1eba0f602e200brianp{
6653a33e820463abd4f81915b7a1eba0f602e200brianp *rv = APR_SUCCESS;
6653a33e820463abd4f81915b7a1eba0f602e200brianp switch(query_code){
6653a33e820463abd4f81915b7a1eba0f602e200brianp case AP_MPMQ_MAX_DAEMON_USED:
6653a33e820463abd4f81915b7a1eba0f602e200brianp *result = ap_daemons_limit;
6653a33e820463abd4f81915b7a1eba0f602e200brianp break;
6653a33e820463abd4f81915b7a1eba0f602e200brianp case AP_MPMQ_IS_THREADED:
6653a33e820463abd4f81915b7a1eba0f602e200brianp *result = AP_MPMQ_NOT_SUPPORTED;
6653a33e820463abd4f81915b7a1eba0f602e200brianp break;
6653a33e820463abd4f81915b7a1eba0f602e200brianp case AP_MPMQ_IS_FORKED:
6653a33e820463abd4f81915b7a1eba0f602e200brianp *result = AP_MPMQ_DYNAMIC;
6653a33e820463abd4f81915b7a1eba0f602e200brianp break;
6653a33e820463abd4f81915b7a1eba0f602e200brianp case AP_MPMQ_HARD_LIMIT_DAEMONS:
6653a33e820463abd4f81915b7a1eba0f602e200brianp *result = server_limit;
6653a33e820463abd4f81915b7a1eba0f602e200brianp break;
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick case AP_MPMQ_HARD_LIMIT_THREADS:
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick *result = HARD_THREAD_LIMIT;
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick break;
239f998fbee5ac5b114b965bb76e217cce0003edstoddard case AP_MPMQ_MAX_THREADS:
3568de757bac0b47256647504c186d17ca272f85rbb *result = 1;
3568de757bac0b47256647504c186d17ca272f85rbb break;
3568de757bac0b47256647504c186d17ca272f85rbb case AP_MPMQ_MIN_SPARE_DAEMONS:
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick *result = ap_daemons_min_free;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard break;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard case AP_MPMQ_MIN_SPARE_THREADS:
3568de757bac0b47256647504c186d17ca272f85rbb *result = 0;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz break;
48d2edbfb84e5559b5da0f8d614ccab805cc67a8rbb case AP_MPMQ_MAX_SPARE_DAEMONS:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *result = ap_daemons_max_free;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard break;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case AP_MPMQ_MAX_SPARE_THREADS:
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton *result = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding break;
3568de757bac0b47256647504c186d17ca272f85rbb case AP_MPMQ_MAX_REQUESTS_DAEMON:
3568de757bac0b47256647504c186d17ca272f85rbb *result = ap_max_requests_per_child;
3568de757bac0b47256647504c186d17ca272f85rbb break;
3568de757bac0b47256647504c186d17ca272f85rbb case AP_MPMQ_MAX_DAEMONS:
3568de757bac0b47256647504c186d17ca272f85rbb *result = ap_daemons_limit;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard break;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard case AP_MPMQ_MPM_STATE:
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz *result = mpm_state;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz break;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard case AP_MPMQ_GENERATION:
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem *result = retained->my_generation;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem break;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem default:
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem *rv = APR_ENOTIMPL;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem break;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem }
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem return OK;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem}
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluemstatic apr_status_t prefork_note_child_killed(int childnum)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard{
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem ap_scoreboard_image->parent[childnum].pid = 0;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard return APR_SUCCESS;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard}
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddardstatic const char *prefork_get_name(void)
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton{
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard return "prefork";
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard}
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard/*****************************************************************
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * Connection structures and accounting...
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
3568de757bac0b47256647504c186d17ca272f85rbbstatic void just_die(int sig)
3568de757bac0b47256647504c186d17ca272f85rbb{
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick clean_child_exit(0);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick}
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick/* volatile because they're updated from a signal handler */
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstatic int volatile shutdown_pending;
e8f95a682820a599fe41b22977010636be5c2717jimstatic int volatile restart_pending;
98cd3186185bb28ae6c95a3f159899fcf56a663ftrawickstatic int volatile die_now = 0;
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawickstatic void stop_listening(int sig)
3568de757bac0b47256647504c186d17ca272f85rbb{
a72ba68ecbbc61e4b513e50d6000245c33f753dcwrowe mpm_state = AP_MPMQ_STOPPING;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ap_close_listeners();
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* For a graceful stop, we want the child to exit when done */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm die_now = 1;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm}
3cbd177a6c885562f9ad0cf11695f044489c881dgregames
3cbd177a6c885562f9ad0cf11695f044489c881dgregamesstatic void sig_term(int sig)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard{
3cbd177a6c885562f9ad0cf11695f044489c881dgregames if (shutdown_pending == 1) {
3cbd177a6c885562f9ad0cf11695f044489c881dgregames /* Um, is this _probably_ not an error, if the user has
3cbd177a6c885562f9ad0cf11695f044489c881dgregames * tried to do a shutdown twice quickly, so we won't
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * worry about reporting it.
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz return;
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames }
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames mpm_state = AP_MPMQ_STOPPING;
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames shutdown_pending = 1;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard retained->is_graceful = (sig == AP_SIG_GRACEFUL_STOP);
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm}
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * in the parent process, unless running in ONE_PROCESS mode
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard */
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstatic void restart(int sig)
7cd5419264796cfeaf8215383cf0f89130a81fectrawick{
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (restart_pending == 1) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick /* Probably not an error - don't bother reporting it */
7cd5419264796cfeaf8215383cf0f89130a81fectrawick return;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick mpm_state = AP_MPMQ_STOPPING;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick restart_pending = 1;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick retained->is_graceful = (sig == AP_SIG_GRACEFUL);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick}
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstatic void set_signals(void)
7cd5419264796cfeaf8215383cf0f89130a81fectrawick{
7cd5419264796cfeaf8215383cf0f89130a81fectrawick#ifndef NO_USE_SIGACTION
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct sigaction sa;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick#endif
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (!one_process) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick ap_fatal_signal_setup(ap_server_conf, pconf);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick#ifndef NO_USE_SIGACTION
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard sigemptyset(&sa.sa_mask);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz sa.sa_flags = 0;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard sa.sa_handler = sig_term;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (sigaction(SIGTERM, &sa, NULL) < 0)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#ifdef AP_SIG_GRACEFUL_STOP
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef SIGINT
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (sigaction(SIGINT, &sa, NULL) < 0)
7cd5419264796cfeaf8215383cf0f89130a81fectrawick ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
7cd5419264796cfeaf8215383cf0f89130a81fectrawick#endif
7cd5419264796cfeaf8215383cf0f89130a81fectrawick#ifdef SIGXCPU
7cd5419264796cfeaf8215383cf0f89130a81fectrawick sa.sa_handler = SIG_DFL;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (sigaction(SIGXCPU, &sa, NULL) < 0)
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");
3568de757bac0b47256647504c186d17ca272f85rbb#endif
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef SIGXFSZ
74fd6d9aeadb9022086259c5c1ae00bc0dda9c9astoddard /* For systems following the LFS standard, ignoring SIGXFSZ allows
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp * a write() beyond the 2GB limit to fail gracefully with E2BIG
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp * rather than terminate the process. */
3568de757bac0b47256647504c186d17ca272f85rbb sa.sa_handler = SIG_IGN;
3568de757bac0b47256647504c186d17ca272f85rbb if (sigaction(SIGXFSZ, &sa, NULL) < 0)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#ifdef SIGPIPE
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard sa.sa_handler = SIG_IGN;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (sigaction(SIGPIPE, &sa, NULL) < 0)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");
1ce78cf71b5baaf2c1ab48e818cb1f2397df5010trawick#endif
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * processing one
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz sigaddset(&sa.sa_mask, SIGHUP);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz sa.sa_handler = restart;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (sigaction(SIGHUP, &sa, NULL) < 0)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#else
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (!one_process) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#ifdef SIGXCPU
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_signal(SIGXCPU, SIG_DFL);
3568de757bac0b47256647504c186d17ca272f85rbb#endif /* SIGXCPU */
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef SIGXFSZ
3568de757bac0b47256647504c186d17ca272f85rbb apr_signal(SIGXFSZ, SIG_IGN);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif /* SIGXFSZ */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
f714f1a7002928d785e53e70349700a7f595fee3trawick
f714f1a7002928d785e53e70349700a7f595fee3trawick apr_signal(SIGTERM, sig_term);
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef SIGHUP
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard apr_signal(SIGHUP, restart);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#endif /* SIGHUP */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#ifdef AP_SIG_GRACEFUL
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz apr_signal(AP_SIG_GRACEFUL, restart);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz#endif /* AP_SIG_GRACEFUL */
3568de757bac0b47256647504c186d17ca272f85rbb#ifdef AP_SIG_GRACEFUL_STOP
3568de757bac0b47256647504c186d17ca272f85rbb apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif /* AP_SIG_GRACEFUL */
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim#ifdef SIGPIPE
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_signal(SIGPIPE, SIG_IGN);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif /* SIGPIPE */
3568de757bac0b47256647504c186d17ca272f85rbb
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard}
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard/*****************************************************************
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * Child process main loop.
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * The following vars are static to avoid getting clobbered by longjmp();
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * they are really private to child_main.
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddardstatic int requests_this_child;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddardstatic int num_listensocks = 0;
3568de757bac0b47256647504c186d17ca272f85rbb
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddardstatic void child_main(int child_num_arg)
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard{
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#if APR_HAS_THREADS
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_thread_t *thd = NULL;
3568de757bac0b47256647504c186d17ca272f85rbb apr_os_thread_t osthd;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_pool_t *ptrans;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_allocator_t *allocator;
3568de757bac0b47256647504c186d17ca272f85rbb apr_status_t status;
3568de757bac0b47256647504c186d17ca272f85rbb int i;
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim ap_listen_rec *lr;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_pollset_t *pollset;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_sb_handle_t *sbh;
3568de757bac0b47256647504c186d17ca272f85rbb apr_bucket_alloc_t *bucket_alloc;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz int last_poll_idx = 0;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard const char *lockfile;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
3568de757bac0b47256647504c186d17ca272f85rbb * child initializes
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard my_child_num = child_num_arg;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_my_pid = getpid();
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard requests_this_child = 0;
3568de757bac0b47256647504c186d17ca272f85rbb
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_fatal_signal_child_setup(ap_server_conf);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* Get a sub context for global allocations in this child, so that
3568de757bac0b47256647504c186d17ca272f85rbb * we can have cleanups occur when the child exits.
3568de757bac0b47256647504c186d17ca272f85rbb */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz apr_allocator_create(&allocator);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz apr_allocator_max_free_set(allocator, ap_max_mem_free);
3568de757bac0b47256647504c186d17ca272f85rbb apr_pool_create_ex(&pchild, pconf, NULL, allocator);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_allocator_owner_set(allocator, pchild);
3568de757bac0b47256647504c186d17ca272f85rbb apr_pool_tag(pchild, "pchild");
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#if APR_HAS_THREADS
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard osthd = apr_os_thread_current();
3568de757bac0b47256647504c186d17ca272f85rbb apr_os_thread_put(&thd, &osthd, pchild);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard#endif
3568de757bac0b47256647504c186d17ca272f85rbb
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick apr_pool_create(&ptrans, pchild);
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick apr_pool_tag(ptrans, "transaction");
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* needs to be done before we switch UIDs so we have permissions */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ap_reopen_scoreboard(pchild, NULL, 0);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz lockfile = apr_proc_mutex_lockfile(accept_mutex);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard status = apr_proc_mutex_child_init(&accept_mutex,
beb70d51e435dc36c56a72b6cd83556c04db9283wrowe lockfile,
fe6baec9bbcd36f932b71a355120cd7b5a685d6cfielding pchild);
3568de757bac0b47256647504c186d17ca272f85rbb if (status != APR_SUCCESS) {
3568de757bac0b47256647504c186d17ca272f85rbb ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard "Couldn't initialize cross-process lock in child "
3568de757bac0b47256647504c186d17ca272f85rbb "(%s) (%s)",
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard lockfile ? lockfile : "none",
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard apr_proc_mutex_name(accept_mutex));
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard clean_child_exit(APEXIT_CHILDFATAL);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (ap_run_drop_privileges(pchild, ap_server_conf)) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard clean_child_exit(APEXIT_CHILDFATAL);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_run_child_init(pchild, ap_server_conf);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* Set up the pollfd array */
8e9734d1a4af74c141e2a0f880bb51bb061fa03atrawick status = apr_pollset_create(&pollset, num_listensocks, pchild, 0);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (status != APR_SUCCESS) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard "Couldn't create pollset in child; check system or user limits");
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick }
3568de757bac0b47256647504c186d17ca272f85rbb
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe apr_pollfd_t pfd = { 0 };
0f113d7123e8bd3e3e2e9b6373461a1a773bfccatrawick
0f113d7123e8bd3e3e2e9b6373461a1a773bfccatrawick pfd.desc_type = APR_POLL_SOCKET;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz pfd.desc.s = lr->sd;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard pfd.reqevents = APR_POLLIN;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard pfd.client_data = lr;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard status = apr_pollset_add(pollset, &pfd);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (status != APR_SUCCESS) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
3568de757bac0b47256647504c186d17ca272f85rbb "Couldn't add listener to pollset; check system or user limits");
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard clean_child_exit(APEXIT_CHILDSICK);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard lr->accept_func = ap_unixd_accept;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb mpm_state = AP_MPMQ_RUNNING;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick bucket_alloc = apr_bucket_alloc_create(pchild);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* die_now is set when AP_SIG_GRACEFUL is received in the child;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * shutdown_pending is set when SIGTERM is received when running
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * in single process mode. */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick while (!die_now && !shutdown_pending) {
f886987cd0bd4220c14043c4d9be77ec22902e73trawick conn_rec *current_conn;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick void *csd;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /*
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * (Re)initialize this child to a pre-connection state.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz apr_pool_clear(ptrans);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if ((ap_max_requests_per_child > 0
a72ba68ecbbc61e4b513e50d6000245c33f753dcwrowe && requests_this_child++ >= ap_max_requests_per_child)) {
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick clean_child_exit(0);
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm }
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick /*
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick * Wait for an acceptable connection to arrive.
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm */
3568de757bac0b47256647504c186d17ca272f85rbb
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* Lock around "accept", if necessary */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz SAFE_ACCEPT(accept_mutex_on());
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (num_listensocks == 1) {
e8f95a682820a599fe41b22977010636be5c2717jim /* There is only one listener record, so refer to that one. */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm lr = ap_listeners;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz else {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* multiple listening sockets - need to poll */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm for (;;) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm apr_int32_t numdesc;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm const apr_pollfd_t *pdesc;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /* check for termination first so we don't sleep for a while in
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * poll if already signalled
36c8049de63c446926139936c3d195330a0539cetrawick */
36c8049de63c446926139936c3d195330a0539cetrawick if (die_now /* in graceful stop/restart */
36c8049de63c446926139936c3d195330a0539cetrawick || (one_process && shutdown_pending)) {
36c8049de63c446926139936c3d195330a0539cetrawick SAFE_ACCEPT(accept_mutex_off());
36c8049de63c446926139936c3d195330a0539cetrawick clean_child_exit(0);
36c8049de63c446926139936c3d195330a0539cetrawick }
36c8049de63c446926139936c3d195330a0539cetrawick
36c8049de63c446926139936c3d195330a0539cetrawick /* timeout == 10 seconds to avoid a hang at graceful restart/stop
e8f95a682820a599fe41b22977010636be5c2717jim * caused by the closing of sockets by the signal handler
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm status = apr_pollset_poll(pollset, apr_time_from_sec(10),
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick &numdesc, &pdesc);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (status != APR_SUCCESS) {
36c8049de63c446926139936c3d195330a0539cetrawick if (APR_STATUS_IS_TIMEUP(status) ||
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick APR_STATUS_IS_EINTR(status)) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick continue;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* Single Unix documents select as returning errnos
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe * EBADF, EINTR, and EINVAL... and in none of those
36c8049de63c446926139936c3d195330a0539cetrawick * cases does it make sense to continue. In fact
36c8049de63c446926139936c3d195330a0539cetrawick * on Linux 2.0.x we seem to end up with EFAULT
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * occasionally, and we'd loop forever due to it.
e8f95a682820a599fe41b22977010636be5c2717jim */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ap_log_error(APLOG_MARK, APLOG_ERR, status,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_server_conf, "apr_pollset_poll: (listen)");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick SAFE_ACCEPT(accept_mutex_off());
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick clean_child_exit(1);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* We can always use pdesc[0], but sockets at position N
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * could end up completely starved of attention in a very
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * busy server. Therefore, we round-robin across the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * returned set of descriptors. While it is possible that
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * the returned set of descriptors might flip around and
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * continue to starve some sockets, we happen to know the
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * internal pollset implementation retains ordering
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * stability of the sockets. Thus, the round-robin should
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * ensure that a socket will eventually be serviced.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (last_poll_idx >= numdesc)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick last_poll_idx = 0;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* Grab a listener record from the client_data of the poll
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * descriptor, and advance our saved index to round-robin
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * the next fetch.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick *
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * ### hmm... this descriptor might have POLLERR rather
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * ### than POLLIN
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick lr = pdesc[last_poll_idx++].client_data;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick goto got_fd;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick got_fd:
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* if we accept() something we don't want to die, so we have to
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * defer the exit
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick status = lr->accept_func(&csd, lr, ptrans);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
e8f95a682820a599fe41b22977010636be5c2717jim if (status == APR_EGENERAL) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* resource shortage or should-not-occur occured */
f886987cd0bd4220c14043c4d9be77ec22902e73trawick clean_child_exit(1);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
f886987cd0bd4220c14043c4d9be77ec22902e73trawick else if (status != APR_SUCCESS) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick continue;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick }
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm /*
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * We now have a connection, so set it up with the appropriate
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * socket options, file descriptors, and read/write buffers.
3568de757bac0b47256647504c186d17ca272f85rbb */
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (current_conn) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#if APR_HAS_THREADS
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick current_conn->current_thread = thd;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#endif
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_process_connection(current_conn, csd);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_lingering_close(current_conn);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* Check the pod and the generation number after processing a
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * connection so that we'll go away if a graceful restart occurred
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * while we were processing the connection or we are the lucky
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * idle server process that gets to die.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton die_now = 1;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm else if (retained->my_generation !=
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_scoreboard_image->global->running_generation) { /* restart? */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* yeah, this could be non-graceful restart, in which case the
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * parent will kill us soon enough, but why bother checking?
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick die_now = 1;
36c8049de63c446926139936c3d195330a0539cetrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_pool_clear(ptrans); /* kludge to avoid crash in APR reslist cleanup code */
f886987cd0bd4220c14043c4d9be77ec22902e73trawick clean_child_exit(0);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick}
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
36c8049de63c446926139936c3d195330a0539cetrawickstatic int make_child(server_rec *s, int slot)
36c8049de63c446926139936c3d195330a0539cetrawick{
36c8049de63c446926139936c3d195330a0539cetrawick int pid;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
e8f95a682820a599fe41b22977010636be5c2717jim if (slot + 1 > retained->max_daemons_limit) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm retained->max_daemons_limit = slot + 1;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (one_process) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(SIGHUP, sig_term);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(SIGINT, sig_term);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#ifdef SIGQUIT
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(SIGQUIT, SIG_DFL);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#endif
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(SIGTERM, sig_term);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_scoreboard_image->parent[slot].pid = getpid();
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick child_main(slot);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* NOTREACHED */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick (request_rec *) NULL);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#ifdef _OSD_POSIX
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* BS2000 requires a "special" version of fork() before a setuid() call */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if ((pid = os_fork(ap_unixd_config.user_name)) == -1) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#else
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if ((pid = fork()) == -1) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#endif
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* fork didn't succeed. Fix the scoreboard or else
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * it will say SERVER_STARTING forever and ever
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick (request_rec *) NULL);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* In case system resources are maxxed out, we don't want
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * Apache running away with the CPU trying to fork over and
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * over and over again.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
e8f95a682820a599fe41b22977010636be5c2717jim sleep(10);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick return -1;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
f886987cd0bd4220c14043c4d9be77ec22902e73trawick if (!pid) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick#ifdef HAVE_BINDPROCESSOR
f886987cd0bd4220c14043c4d9be77ec22902e73trawick /* by default AIX binds to a single processor
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm * this bit unbinds children which will then bind to another cpu
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm */
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm int status = bindprocessor(BINDPROCESS, (int)getpid(),
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm PROCESSOR_CLASS_ANY);
3568de757bac0b47256647504c186d17ca272f85rbb if (status != OK) {
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp ap_log_error(APLOG_MARK, APLOG_DEBUG, errno,
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp ap_server_conf, "processor unbind failed");
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
e8f95a682820a599fe41b22977010636be5c2717jim#endif
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick RAISE_SIGSTOP(MAKE_CHILD);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick AP_MONCONTROL(1);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* Disable the parent's signal handlers and set up proper handling in
e8f95a682820a599fe41b22977010636be5c2717jim * the child.
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(SIGHUP, just_die);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(SIGTERM, just_die);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* The child process just closes listeners on AP_SIG_GRACEFUL.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * The pod is used for signalling the graceful restart.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick apr_signal(AP_SIG_GRACEFUL, stop_listening);
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm child_main(slot);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ap_scoreboard_image->parent[slot].pid = pid;
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton return 0;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick}
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz/* start up a bunch of children */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickstatic void startup_children(int number_to_start)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz{
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe int i;
3568de757bac0b47256647504c186d17ca272f85rbb
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe continue;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick }
f886987cd0bd4220c14043c4d9be77ec22902e73trawick if (make_child(ap_server_conf, i) < 0) {
f886987cd0bd4220c14043c4d9be77ec22902e73trawick break;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick }
f886987cd0bd4220c14043c4d9be77ec22902e73trawick --number_to_start;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick }
f886987cd0bd4220c14043c4d9be77ec22902e73trawick}
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowestatic void perform_idle_server_maintenance(apr_pool_t *p)
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe{
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe int i;
3568de757bac0b47256647504c186d17ca272f85rbb int idle_count;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz worker_score *ws;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick int free_length;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz int free_slots[MAX_SPAWN_RATE];
3568de757bac0b47256647504c186d17ca272f85rbb int last_non_dead;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz int total_non_dead;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz /* initialize the free_list */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz free_length = 0;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbb idle_count = 0;
3568de757bac0b47256647504c186d17ca272f85rbb last_non_dead = -1;
98fb535f829e2a95aabd82420931f476661fa8e3jorton total_non_dead = 0;
98fb535f829e2a95aabd82420931f476661fa8e3jorton
e8f95a682820a599fe41b22977010636be5c2717jim for (i = 0; i < ap_daemons_limit; ++i) {
e8f95a682820a599fe41b22977010636be5c2717jim int status;
98fb535f829e2a95aabd82420931f476661fa8e3jorton
98fb535f829e2a95aabd82420931f476661fa8e3jorton if (i >= retained->max_daemons_limit && free_length == retained->idle_spawn_rate)
e8f95a682820a599fe41b22977010636be5c2717jim break;
98fb535f829e2a95aabd82420931f476661fa8e3jorton ws = &ap_scoreboard_image->servers[i][0];
98fb535f829e2a95aabd82420931f476661fa8e3jorton status = ws->status;
98fb535f829e2a95aabd82420931f476661fa8e3jorton if (status == SERVER_DEAD) {
3568de757bac0b47256647504c186d17ca272f85rbb /* try to keep children numbers as low as possible */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (free_length < retained->idle_spawn_rate) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz free_slots[free_length] = i;
3568de757bac0b47256647504c186d17ca272f85rbb ++free_length;
3568de757bac0b47256647504c186d17ca272f85rbb }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* We consider a starting server as idle because we started it
3568de757bac0b47256647504c186d17ca272f85rbb * at least a cycle ago, and if it still hasn't finished starting
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * then we're just going to swamp things worse by forking more.
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz * So we hopefully won't need to fork more if we count it.
3568de757bac0b47256647504c186d17ca272f85rbb * This depends on the ordering of SERVER_READY and SERVER_STARTING.
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz */
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (status <= SERVER_READY) {
3568de757bac0b47256647504c186d17ca272f85rbb ++ idle_count;
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb ++total_non_dead;
3568de757bac0b47256647504c186d17ca272f85rbb last_non_dead = i;
3568de757bac0b47256647504c186d17ca272f85rbb }
ec020ca384efb30d501a5af796ddc3bb237d7b8fgregames }
3568de757bac0b47256647504c186d17ca272f85rbb retained->max_daemons_limit = last_non_dead + 1;
ce03576b2434cec77f2921db9d5b6a0510581c23rederpj if (idle_count > ap_daemons_max_free) {
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick /* kill off one child... we use the pod because that'll cause it to
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick * shut down gracefully, in case it happened to pick up a request
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh * while we were counting
3568de757bac0b47256647504c186d17ca272f85rbb */
3568de757bac0b47256647504c186d17ca272f85rbb ap_mpm_pod_signal(pod);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick retained->idle_spawn_rate = 1;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick else if (idle_count < ap_daemons_min_free) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick /* terminate the free list */
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (free_length == 0) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick /* only report this condition once */
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (!retained->maxclients_reported) {
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "server reached MaxClients setting, consider"
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe " raising the MaxClients setting");
3568de757bac0b47256647504c186d17ca272f85rbb retained->maxclients_reported = 1;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick retained->idle_spawn_rate = 1;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
ca53a74f4012a45cbad48e940eddf27d866981f9dougm else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (retained->idle_spawn_rate >= 8) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "server seems busy, (you may need "
302dc1f7b3feee23a91ad8f3cf3cb2edd95a557bmanoj "to increase StartServers, or Min/MaxSpareServers), "
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "spawning %d children, there are %d idle, and "
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz "%d total children", retained->idle_spawn_rate,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz idle_count, total_non_dead);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz for (i = 0; i < free_length; ++i) {
3568de757bac0b47256647504c186d17ca272f85rbb make_child(ap_server_conf, free_slots[i]);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
3568de757bac0b47256647504c186d17ca272f85rbb /* 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 (retained->hold_off_on_exponential_spawning) {
--retained->hold_off_on_exponential_spawning;
}
else if (retained->idle_spawn_rate < MAX_SPAWN_RATE) {
retained->idle_spawn_rate *= 2;
}
}
}
else {
retained->idle_spawn_rate = 1;
}
}
/*****************************************************************
* Executive routines.
*/
static int prefork_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);
/* Initialize cross-process accept lock */
rv = ap_proc_mutex_create(&accept_mutex, NULL, AP_ACCEPT_MUTEX_TYPE, NULL,
s, _pconf, 0);
if (rv != APR_SUCCESS) {
mpm_state = AP_MPMQ_STOPPING;
return DONE;
}
if (!retained->is_graceful) {
if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
mpm_state = AP_MPMQ_STOPPING;
return DONE;
}
/* fix the generation number in the global score; we just got a new,
* cleared scoreboard
*/
ap_scoreboard_image->global->running_generation = retained->my_generation;
}
set_signals();
if (one_process) {
AP_MONCONTROL(1);
make_child(ap_server_conf, 0);
/* NOTREACHED */
}
else {
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 (!retained->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
*/
retained->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_description());
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
"Server built: %s", ap_get_server_built());
ap_log_command_line(plog, s);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Accept mutex: %s (default: %s)",
apr_proc_mutex_name(accept_mutex),
apr_proc_mutex_defname());
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, ap_server_conf);
/* 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 DONE;
}
/* non-fatal death... note that it's gone in the scoreboard. */
child_slot = ap_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
*/
retained->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_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) {
/* handled */
#endif
}
else if (retained->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);
}
} /* one_process */
mpm_state = AP_MPMQ_STOPPING;
if (shutdown_pending && !retained->is_graceful) {
/* Time to shut down:
* Kill child processes, tell them to call child_exit, etc...
*/
if (ap_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 */
ap_remove_pid(pconf, ap_pid_fname);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
"caught SIGTERM, shutting down");
return DONE;
} else if (shutdown_pending) {
/* Time to perform a graceful shut down:
* Reap the inactive children, and ask the active ones
* to close their listeners, then wait until they are
* all done to exit.
*/
int active_children;
apr_time_t cutoff = 0;
/* Stop listening */
ap_close_listeners();
/* kill off the idle ones */
ap_mpm_pod_killpg(pod, retained->max_daemons_limit);
/* Send SIGUSR1 to the active children */
active_children = 0;
for (index = 0; index < ap_daemons_limit; ++index) {
if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
/* Ask each child to close its listeners. */
ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL);
active_children++;
}
}
/* Allow each child which actually finished to exit */
ap_relieve_child_processes();
/* cleanup pid file */
ap_remove_pid(pconf, ap_pid_fname);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
"caught " AP_SIG_GRACEFUL_STOP_STRING ", shutting down gracefully");
if (ap_graceful_shutdown_timeout) {
cutoff = apr_time_now() +
apr_time_from_sec(ap_graceful_shutdown_timeout);
}
/* Don't really exit until each child has finished */
shutdown_pending = 0;
do {
/* Pause for a second */
sleep(1);
/* Relieve any children which have now exited */
ap_relieve_child_processes();
active_children = 0;
for (index = 0; index < ap_daemons_limit; ++index) {
if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
active_children = 1;
/* Having just one child is enough to stay around */
break;
}
}
} while (!shutdown_pending && active_children &&
(!ap_graceful_shutdown_timeout || apr_time_now() < cutoff));
/* We might be here because we received SIGTERM, either
* way, try and make sure that all of our processes are
* really dead.
*/
ap_unixd_killpg(getpgrp(), SIGTERM);
return DONE;
}
/* we've been told to restart */
apr_signal(SIGHUP, SIG_IGN);
apr_signal(AP_SIG_GRACEFUL, SIG_IGN);
if (one_process) {
/* not worth thinking about */
return DONE;
}
/* 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.
*/
++retained->my_generation;
ap_scoreboard_image->global->running_generation = retained->my_generation;
if (retained->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, retained->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;
/* Ask each child to close its listeners.
*
* NOTE: we use the scoreboard, because if we send SIGUSR1
* to every process in the group, this may include CGI's,
* piped loggers, etc. They almost certainly won't handle
* it gracefully.
*/
ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL);
}
}
}
else {
/* Kill 'em off */
if (ap_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 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 prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
int startup = 0;
int level_flags = 0;
apr_status_t rv;
pconf = p;
/* the reverse of pre_config, we want this only the first time around */
if (retained->module_loads == 1) {
startup = 1;
level_flags |= APLOG_STARTUP;
}
if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
(startup ? NULL : s),
"no listening sockets available, shutting down");
return DONE;
}
if ((rv = ap_mpm_pod_open(pconf, &pod))) {
ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
(startup ? NULL : s),
"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)
{
int no_detach, debug, foreground;
apr_status_t rv;
const char *userdata_key = "mpm_prefork_module";
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");
}
ap_mutex_register(p, AP_ACCEPT_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0);
/* sigh, want this only the second time around */
retained = ap_retained_data_get(userdata_key);
if (!retained) {
retained = ap_retained_data_create(userdata_key, sizeof(*retained));
retained->max_daemons_limit = -1;
retained->idle_spawn_rate = 1;
}
++retained->module_loads;
if (retained->module_loads == 2) {
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();
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;
server_limit = DEFAULT_SERVER_LIMIT;
ap_daemons_limit = server_limit;
ap_pid_fname = DEFAULT_PIDLOG;
ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
ap_extended_status = 0;
ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
return OK;
}
static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
int startup = 0;
/* the reverse of pre_config, we want this only the first time around */
if (retained->module_loads == 1) {
startup = 1;
}
if (server_limit > MAX_SERVER_LIMIT) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: ServerLimit of %d exceeds compile-time "
"limit of", server_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" %d servers, decreasing to %d.",
MAX_SERVER_LIMIT, MAX_SERVER_LIMIT);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"ServerLimit of %d exceeds compile-time limit "
"of %d, decreasing to match",
server_limit, MAX_SERVER_LIMIT);
}
server_limit = MAX_SERVER_LIMIT;
}
else if (server_limit < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: ServerLimit of %d not allowed, "
"increasing to 1.", server_limit);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"ServerLimit of %d not allowed, increasing to 1",
server_limit);
}
server_limit = 1;
}
/* you cannot change ServerLimit across a restart; ignore
* any such attempts
*/
if (!retained->first_server_limit) {
retained->first_server_limit = server_limit;
}
else if (server_limit != retained->first_server_limit) {
/* don't need a startup console version here */
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"changing ServerLimit to %d from original value of %d "
"not allowed during restart",
server_limit, retained->first_server_limit);
server_limit = retained->first_server_limit;
}
if (ap_daemons_limit > server_limit) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: MaxClients of %d exceeds ServerLimit "
"value of", ap_daemons_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" %d servers, decreasing MaxClients to %d.",
server_limit, server_limit);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" To increase, please see the ServerLimit "
"directive.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"MaxClients of %d exceeds ServerLimit value "
"of %d, decreasing to match",
ap_daemons_limit, server_limit);
}
ap_daemons_limit = server_limit;
}
else if (ap_daemons_limit < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: MaxClients of %d not allowed, "
"increasing to 1.", ap_daemons_limit);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"MaxClients of %d not allowed, increasing to 1",
ap_daemons_limit);
}
ap_daemons_limit = 1;
}
/* ap_daemons_to_start > ap_daemons_limit checked in prefork_run() */
if (ap_daemons_to_start < 0) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: StartServers of %d not allowed, "
"increasing to 1.", ap_daemons_to_start);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"StartServers of %d not allowed, increasing to 1",
ap_daemons_to_start);
}
ap_daemons_to_start = 1;
}
if (ap_daemons_min_free < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: MinSpareServers of %d not allowed, "
"increasing to 1", ap_daemons_min_free);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" to avoid almost certain server failure.");
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" Please read the documentation.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"MinSpareServers of %d not allowed, increasing to 1",
ap_daemons_min_free);
}
ap_daemons_min_free = 1;
}
/* ap_daemons_max_free < ap_daemons_min_free + 1 checked in prefork_run() */
return OK;
}
static void prefork_hooks(apr_pool_t *p)
{
/* Our open_logs hook function 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_open_logs(prefork_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
/* 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);
ap_hook_check_config(prefork_check_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm(prefork_run, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_query(prefork_query, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_note_child_killed(prefork_note_child_killed, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_mpm_get_name(prefork_get_name, 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_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);
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);
return NULL;
}
static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
server_limit = atoi(arg);
return NULL;
}
static const command_rec prefork_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("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"),
AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND,
{ NULL }
};
AP_DECLARE_MODULE(mpm_prefork) = {
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 */
prefork_cmds, /* command apr_table_t */
prefork_hooks, /* register hooks */
};