From: Chris Darroch
In addition to the set of active child processes, there may be additional child processes which are terminating, but where at diff --git a/include/http_config.h b/include/http_config.h index 5e9fd51d0d5..820a9facafc 100644 --- a/include/http_config.h +++ b/include/http_config.h @@ -984,6 +984,16 @@ AP_DECLARE_HOOK(int,header_parser,(request_rec *r)) AP_DECLARE_HOOK(int,pre_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp)) +/** + * Run the check_config function for each module + * @param pconf The config pool + * @param plog The logging streams pool + * @param ptemp The temporary pool + * @return OK or DECLINED on success anything else is a error + */ +AP_DECLARE_HOOK(int,check_config,(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s)) + /** * Run the test_config function for each module; this hook is run * only if the server was invoked to test the configuration syntax. diff --git a/modules/experimental/mod_example.c b/modules/experimental/mod_example.c index 1b343fb0584..f26ddf8867c 100644 --- a/modules/experimental/mod_example.c +++ b/modules/experimental/mod_example.c @@ -829,8 +829,31 @@ static int x_pre_config(apr_pool_t *pconf, apr_pool_t *plog, } /* - * This routine is called to perform any module-specific fixing of header - * fields, et cetera. It is invoked just before any content-handler. + * This routine is called after the server processes the configuration + * files. At this point the module may review and adjust its configuration + * settings in relation to one another and report any problems. On restart, + * this routine will be called twice, once in the startup process (which + * exits shortly after this phase) and once in the running server process. + * + * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the + * server will still call any remaining modules with an handler for this + * phase. + */ +static int x_check_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + /* + * Log the call and exit. + */ + trace_add(NULL, NULL, NULL, "x_check_config()"); + return OK; +} + +/* + * This routine is called after the server finishes the configuration + * process. At this point the module may review and adjust its configuration + * settings in relation to one another and report any problems. On restart, + * this routine will be called only once, in the running server process. * * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the * server will still call any remaining modules with an handler for this @@ -1274,6 +1297,7 @@ static int x_logger(request_rec *r) static void x_register_hooks(apr_pool_t *p) { ap_hook_pre_config(x_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_config(x_check_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(x_post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_open_logs(x_open_logs, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(x_child_init, NULL, NULL, APR_HOOK_MIDDLE); diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c index ad2b57f32c3..a999080b0cb 100644 --- a/modules/generators/mod_info.c +++ b/modules/generators/mod_info.c @@ -236,6 +236,7 @@ typedef struct static hook_lookup_t startup_hooks[] = { {"Pre-Config", ap_hook_get_pre_config}, + {"Check Configuration", ap_hook_get_check_config}, {"Test Configuration", ap_hook_get_test_config}, {"Post Configuration", ap_hook_get_post_config}, {"Open Logs", ap_hook_get_open_logs}, diff --git a/server/config.c b/server/config.c index 8eed98b0638..4e1799e7443 100644 --- a/server/config.c +++ b/server/config.c @@ -67,6 +67,7 @@ AP_DECLARE_DATA ap_directive_t *ap_conftree = NULL; APR_HOOK_STRUCT( APR_HOOK_LINK(header_parser) APR_HOOK_LINK(pre_config) + APR_HOOK_LINK(check_config) APR_HOOK_LINK(post_config) APR_HOOK_LINK(open_logs) APR_HOOK_LINK(child_init) @@ -84,6 +85,11 @@ AP_IMPLEMENT_HOOK_RUN_ALL(int, pre_config, apr_pool_t *ptemp), (pconf, plog, ptemp), OK, DECLINED) +AP_IMPLEMENT_HOOK_RUN_ALL(int, check_config, + (apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s), + (pconf, plog, ptemp, s), OK, DECLINED) + AP_IMPLEMENT_HOOK_VOID(test_config, (apr_pool_t *pconf, server_rec *s), (pconf, s)) diff --git a/server/main.c b/server/main.c index e85fba6656f..c968bf9cf98 100644 --- a/server/main.c +++ b/server/main.c @@ -645,6 +645,12 @@ int main(int argc, const char * const argv[]) ap_fini_vhost_config(pconf, server_conf); apr_hook_sort_all(); + if (ap_run_check_config(pconf, plog, ptemp, server_conf) != OK) { + ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0, + NULL, "Configuration check failed"); + destroy_and_exit_process(process, 1); + } + if (configtestonly) { ap_run_test_config(pconf, server_conf); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK"); @@ -716,6 +722,13 @@ int main(int argc, const char * const argv[]) ap_fixup_virtual_hosts(pconf, server_conf); ap_fini_vhost_config(pconf, server_conf); apr_hook_sort_all(); + + if (ap_run_check_config(pconf, plog, ptemp, server_conf) != OK) { + ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0, + NULL, "Configuration check failed"); + destroy_and_exit_process(process, 1); + } + apr_pool_clear(plog); if (ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) { ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, diff --git a/server/mpm/beos/beos.c b/server/mpm/beos/beos.c index b7e4671b068..0a46d8793e9 100644 --- a/server/mpm/beos/beos.c +++ b/server/mpm/beos/beos.c @@ -1078,11 +1078,108 @@ static int beos_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem return OK; } +static int beos_check_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + static int restart_num = 0; + int startup = 0; + + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + startup = 1; + } + + if (ap_thread_limit > HARD_THREAD_LIMIT) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d exceeds compile-time " + "limit of", ap_thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d servers, decreasing to %d.", + HARD_THREAD_LIMIT, HARD_THREAD_LIMIT); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " To increase, please see the HARD_THREAD_LIMIT" + "define in"); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " server/mpm/beos%s.", AP_MPM_HARD_LIMITS_FILE); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxClients of %d exceeds compile-time limit " + "of %d, decreasing to match", + ap_thread_limit, HARD_THREAD_LIMIT); + } + ap_thread_limit = HARD_THREAD_LIMIT; + } + else if (ap_thread_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_thread_limit); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxClients of %d not allowed, increasing to 1", + ap_thread_limit); + } + ap_thread_limit = 1; + } + + /* ap_threads_to_start > ap_thread_limit checked in ap_mpm_run() */ + if (ap_threads_to_start < 0) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: StartThreads of %d not allowed, " + "increasing to 1.", ap_threads_to_start); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "StartThreads of %d not allowed, increasing to 1", + ap_threads_to_start); + } + ap_threads_to_start = 1; + } + + if (min_spare_threads < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MinSpareThreads of %d not allowed, " + "increasing to 1", min_spare_threads); + 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, + "MinSpareThreads of %d not allowed, increasing to 1", + min_spare_threads); + } + min_spare_threads = 1; + } + + /* max_spare_threads < min_spare_threads checked in ap_mpm_run() */ + + if (ap_max_requests_per_thread < 0) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxRequestsPerThread of %d not allowed, " + "increasing to 0,", ap_max_requests_per_thread); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " but this may not be what you want."); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxRequestsPerThread of %d not allowed, " + "increasing to 0", ap_max_requests_per_thread); + } + ap_max_requests_per_thread = 0; + } + + return OK; +} + static void beos_hooks(apr_pool_t *p) { one_process = 0; ap_hook_pre_config(beos_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_config(beos_check_config, NULL, NULL, APR_HOOK_MIDDLE); } static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, const char *arg) @@ -1093,11 +1190,6 @@ static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, const char } ap_threads_to_start = atoi(arg); - if (ap_threads_to_start < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "StartThreads set to a value less than 0, reset to 1"); - ap_threads_to_start = 1; - } return NULL; } @@ -1109,16 +1201,6 @@ static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, const char } min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - return NULL; } @@ -1141,22 +1223,6 @@ static const char *set_threads_limit (cmd_parms *cmd, void *dummy, const char *a } ap_thread_limit = atoi(arg); - if (ap_thread_limit > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,", ap_thread_limit, HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " HARD_THREAD_LIMIT define in server/mpm/beos/mpm_default.h."); - ap_thread_limit = HARD_THREAD_LIMIT; - } - else if (ap_thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to %d", HARD_THREAD_LIMIT); - ap_thread_limit = HARD_THREAD_LIMIT; - } return NULL; } @@ -1168,13 +1234,6 @@ static const char *set_max_requests_per_thread (cmd_parms *cmd, void *dummy, con } ap_max_requests_per_thread = atoi(arg); - if (ap_max_requests_per_thread < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxRequestsPerThread was set below 0" - "reset to 0, but this may not be what you want."); - ap_max_requests_per_thread = 0; - } - return NULL; } diff --git a/server/mpm/experimental/event/event.c b/server/mpm/experimental/event/event.c index 2de0d27cc2c..ea21b5660e2 100644 --- a/server/mpm/experimental/event/event.c +++ b/server/mpm/experimental/event/event.c @@ -145,11 +145,11 @@ static int ap_daemons_to_start = 0; static int min_spare_threads = 0; static int max_spare_threads = 0; static int ap_daemons_limit = 0; -static int server_limit = DEFAULT_SERVER_LIMIT; +static int max_clients = 0; +static int server_limit = 0; static int first_server_limit = 0; -static int thread_limit = DEFAULT_THREAD_LIMIT; +static int thread_limit = 0; static int first_thread_limit = 0; -static int changed_limit_at_restart; static int dying = 0; static int workers_may_exit = 0; static int start_thread_may_exit = 0; @@ -1947,16 +1947,6 @@ int ap_mpm_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) ap_log_pid(pconf, ap_pid_fname); - first_server_limit = server_limit; - first_thread_limit = thread_limit; - - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit or ThreadLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - if (!is_graceful) { if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { mpm_state = AP_MPMQ_STOPPING; @@ -1976,9 +1966,10 @@ int ap_mpm_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) /* 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 + * rapidly... and for each one that exits we may start a new one, until + * there are at least min_spare_threads idle threads, counting across + * all children. But we may be permitted to start more children 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; @@ -2142,21 +2133,32 @@ int ap_mpm_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) static int worker_open_logs(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * s) { + static int restart_num = 0; + int startup = 0; + int level_flags = 0; apr_status_t rv; pconf = p; ap_server_conf = s; + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + startup = 1; + level_flags |= APLOG_STARTUP; + } + if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT | APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); + ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0, + (startup ? NULL : s), + "no listening sockets available, shutting down"); return DONE; } if (!one_process) { if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT | APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); + ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, + (startup ? NULL : s), + "could not open pipe-of-death"); return DONE; } } @@ -2168,49 +2170,10 @@ static int worker_pre_config(apr_pool_t * pconf, apr_pool_t * plog, { static int restart_num = 0; int no_detach, debug, foreground; - ap_directive_t *pdir; - ap_directive_t *max_clients = NULL; apr_status_t rv; mpm_state = AP_MPMQ_STARTING; - /* make sure that "ThreadsPerChild" gets set before "MaxClients" */ - for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) { - if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) { - if (!max_clients) { - /* we're in the clear, got ThreadsPerChild first */ - break; - } - else { - /* now to swap the data */ - ap_directive_t temp; - - temp.directive = pdir->directive; - temp.args = pdir->args; - /* Make sure you don't change 'next', or you may get loops! */ - /* XXX: first_child, parent, and data can never be set - * for these directives, right? -aaron */ - temp.filename = pdir->filename; - temp.line_num = pdir->line_num; - - pdir->directive = max_clients->directive; - pdir->args = max_clients->args; - pdir->filename = max_clients->filename; - pdir->line_num = max_clients->line_num; - - max_clients->directive = temp.directive; - max_clients->args = temp.args; - max_clients->filename = temp.filename; - max_clients->line_num = temp.line_num; - break; - } - } - else if (!max_clients - && strncasecmp(pdir->directive, "MaxClients", 10) == 0) { - max_clients = pdir; - } - } - debug = ap_exists_config_define("DEBUG"); if (debug) { @@ -2253,8 +2216,11 @@ static int worker_pre_config(apr_pool_t * pconf, apr_pool_t * plog, ap_daemons_to_start = DEFAULT_START_DAEMON; min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; + server_limit = DEFAULT_SERVER_LIMIT; + thread_limit = DEFAULT_THREAD_LIMIT; ap_daemons_limit = server_limit; ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; + max_clients = ap_daemons_limit * ap_threads_per_child; ap_pid_fname = DEFAULT_PIDLOG; ap_lock_fname = DEFAULT_LOCKFILE; ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; @@ -2268,20 +2234,258 @@ static int worker_pre_config(apr_pool_t * pconf, apr_pool_t * plog, return OK; } +static int event_check_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + static int restart_num = 0; + int startup = 0; + apr_status_t rv; + + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + 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 (!first_server_limit) { + first_server_limit = server_limit; + } + else if (server_limit != 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, first_server_limit); + server_limit = first_server_limit; + } + + if (thread_limit > MAX_THREAD_LIMIT) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadLimit of %d exceeds compile-time " + "limit of", thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + MAX_THREAD_LIMIT, MAX_THREAD_LIMIT); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadLimit of %d exceeds compile-time limit " + "of %d, decreasing to match", + thread_limit, MAX_THREAD_LIMIT); + } + thread_limit = MAX_THREAD_LIMIT; + } + else if (thread_limit < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadLimit of %d not allowed, " + "increasing to 1.", thread_limit); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadLimit of %d not allowed, increasing to 1", + thread_limit); + } + thread_limit = 1; + } + + /* you cannot change ThreadLimit across a restart; ignore + * any such attempts + */ + if (!first_thread_limit) { + first_thread_limit = thread_limit; + } + else if (thread_limit != first_thread_limit) { + /* don't need a startup console version here */ + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "changing ThreadLimit to %d from original value of %d " + "not allowed during restart", + thread_limit, first_thread_limit); + thread_limit = first_thread_limit; + } + + if (ap_threads_per_child > thread_limit) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " + "of", ap_threads_per_child); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + thread_limit, thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " To increase, please see the ThreadLimit " + "directive."); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadsPerChild of %d exceeds ThreadLimit " + "of %d, decreasing to match", + ap_threads_per_child, thread_limit); + } + ap_threads_per_child = thread_limit; + } + else if (ap_threads_per_child < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadsPerChild of %d not allowed, " + "increasing to 1.", ap_threads_per_child); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadsPerChild of %d not allowed, increasing to 1", + ap_threads_per_child); + } + ap_threads_per_child = 1; + } + + if (max_clients < ap_threads_per_child) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d is less than " + "ThreadsPerChild of", max_clients); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d, increasing to %d. MaxClients must be at " + "least as large", + ap_threads_per_child, ap_threads_per_child); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " as the number of threads in a single server."); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxClients of %d is less than ThreadsPerChild " + "of %d, increasing to match", + max_clients, ap_threads_per_child); + } + max_clients = ap_threads_per_child; + } + + ap_daemons_limit = max_clients / ap_threads_per_child; + + if (max_clients % ap_threads_per_child) { + int tmp_max_clients = ap_daemons_limit * ap_threads_per_child; + + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d is not an integer " + "multiple of", max_clients); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " ThreadsPerChild of %d, decreasing to nearest " + "multiple %d,", ap_threads_per_child, + tmp_max_clients); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " for a maximum of %d servers.", + ap_daemons_limit); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxClients of %d is not an integer multiple of " + "ThreadsPerChild of %d, decreasing to nearest " + "multiple %d", max_clients, ap_threads_per_child, + tmp_max_clients); + } + max_clients = tmp_max_clients; + } + + if (ap_daemons_limit > server_limit) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d would require %d " + "servers and ", max_clients, ap_daemons_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " would exceed ServerLimit of %d, decreasing to %d.", + server_limit, server_limit * ap_threads_per_child); + 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 would require %d servers and " + "exceed ServerLimit of %d, decreasing to %d", + max_clients, ap_daemons_limit, server_limit, + server_limit * ap_threads_per_child); + } + ap_daemons_limit = server_limit; + } + + /* ap_daemons_to_start > ap_daemons_limit checked in ap_mpm_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 (min_spare_threads < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MinSpareThreads of %d not allowed, " + "increasing to 1", min_spare_threads); + 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, + "MinSpareThreads of %d not allowed, increasing to 1", + min_spare_threads); + } + min_spare_threads = 1; + } + + /* max_spare_threads < min_spare_threads + ap_threads_per_child + * checked in ap_mpm_run() + */ + + return OK; +} + static void event_hooks(apr_pool_t * p) { - /* The worker open_logs phase must run before the core's, or stderr + /* 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 }; one_process = 0; - ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); + ap_hook_open_logs(worker_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(worker_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); + ap_hook_check_config(event_check_config, NULL, NULL, APR_HOOK_MIDDLE); } static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, @@ -2305,16 +2509,6 @@ static const char *set_min_spare_threads(cmd_parms * cmd, void *dummy, } min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - return NULL; } @@ -2333,59 +2527,12 @@ static const char *set_max_spare_threads(cmd_parms * cmd, void *dummy, static const char *set_max_clients(cmd_parms * cmd, void *dummy, const char *arg) { - int max_clients; const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - /* It is ok to use ap_threads_per_child here because we are - * sure that it gets set before MaxClients in the pre_config stage. */ max_clients = atoi(arg); - if (max_clients < ap_threads_per_child) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) must be at least as large", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " as ThreadsPerChild (%d). Automatically", - ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " increasing MaxClients to %d.", ap_threads_per_child); - max_clients = ap_threads_per_child; - } - ap_daemons_limit = max_clients / ap_threads_per_child; - if ((max_clients > 0) && (max_clients % ap_threads_per_child)) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) is not an integer multiple", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " of ThreadsPerChild (%d), lowering MaxClients to %d", - ap_threads_per_child, - ap_daemons_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " for a maximum of %d child processes,", - ap_daemons_limit); - max_clients = ap_daemons_limit * ap_threads_per_child; - } - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d would require %d servers,", - max_clients, ap_daemons_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " and would exceed the ServerLimit value of %d.", - server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " Automatically lowering MaxClients to %d. To increase,", - server_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " please see the ServerLimit directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } return NULL; } @@ -2398,101 +2545,28 @@ static const char *set_threads_per_child(cmd_parms * cmd, void *dummy, } ap_threads_per_child = atoi(arg); - if (ap_threads_per_child > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d", ap_threads_per_child, thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "threads, lowering ThreadsPerChild to %d. To increase, " - "please see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } return NULL; } static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) { - int tmp_server_limit; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } + server_limit = atoi(arg); return NULL; } static const char *set_thread_limit(cmd_parms * cmd, void *dummy, const char *arg) { - int tmp_thread_limit; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d servers,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } + thread_limit = atoi(arg); return NULL; } diff --git a/server/mpm/mpmt_os2/mpmt_os2.c b/server/mpm/mpmt_os2/mpmt_os2.c index 8fb10ce9c38..99a75c7f767 100644 --- a/server/mpm/mpmt_os2/mpmt_os2.c +++ b/server/mpm/mpmt_os2/mpmt_os2.c @@ -479,9 +479,56 @@ static int mpmt_os2_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t * +static int mpmt_os2_check_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + static int restart_num = 0; + int startup = 0; + + /* we want this only the first time around */ + if (restart_num++ == 0) { + startup = 1; + } + + 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_min_spare_threads < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MinSpareThreads of %d not allowed, " + "increasing to 1", ap_min_spare_threads); + 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, + "MinSpareThreads of %d not allowed, increasing to 1", + ap_min_spare_threads); + } + ap_min_spare_threads = 1; + } + + return OK; +} + + + static void mpmt_os2_hooks(apr_pool_t *p) { ap_hook_pre_config(mpmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_config(mpmt_os2_check_config, NULL, NULL, APR_HOOK_MIDDLE); } @@ -510,17 +557,6 @@ static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, } ap_min_spare_threads = atoi(arg); - - if (ap_min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - ap_min_spare_threads = 1; - } - return NULL; } diff --git a/server/mpm/netware/mpm_netware.c b/server/mpm/netware/mpm_netware.c index dd4cb3592a4..f116d2b0005 100644 --- a/server/mpm/netware/mpm_netware.c +++ b/server/mpm/netware/mpm_netware.c @@ -995,9 +995,93 @@ static int netware_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp return OK; } +static int netware_check_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + static int restart_num = 0; + int startup = 0; + + /* we want this only the first time around */ + if (restart_num++ == 0) { + startup = 1; + } + + if (ap_threads_limit > HARD_THREAD_LIMIT) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxThreads of %d exceeds compile-time " + "limit of", ap_threads_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + HARD_THREAD_LIMIT, HARD_THREAD_LIMIT); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " To increase, please see the HARD_THREAD_LIMIT" + "define in"); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " server/mpm/netware%s.", AP_MPM_HARD_LIMITS_FILE); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxThreads of %d exceeds compile-time limit " + "of %d, decreasing to match", + ap_threads_limit, HARD_THREAD_LIMIT); + } + ap_threads_limit = HARD_THREAD_LIMIT; + } + else if (ap_threads_limit < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxThreads of %d not allowed, " + "increasing to 1.", ap_threads_limit); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxThreads of %d not allowed, increasing to 1", + ap_threads_limit); + } + ap_threads_limit = 1; + } + + /* ap_threads_to_start > ap_threads_limit effectively checked in + * call to startup_workers(ap_threads_to_start) in ap_mpm_run() + */ + if (ap_threads_to_start < 0) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: StartThreads of %d not allowed, " + "increasing to 1.", ap_threads_to_start); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "StartThreads of %d not allowed, increasing to 1", + ap_threads_to_start); + } + ap_threads_to_start = 1; + } + + if (ap_threads_min_free < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MinSpareThreads of %d not allowed, " + "increasing to 1", ap_threads_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, + "MinSpareThreads of %d not allowed, increasing to 1", + ap_threads_min_free); + } + ap_threads_min_free = 1; + } + + /* ap_threads_max_free < ap_threads_min_free + 1 checked in ap_mpm_run() */ + + return OK; +} + static void netware_mpm_hooks(apr_pool_t *p) { ap_hook_pre_config(netware_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_config(netware_check_config, NULL, NULL, APR_HOOK_MIDDLE); } void netware_rewrite_args(process_rec *process) @@ -1214,16 +1298,6 @@ static const char *set_min_free_threads(cmd_parms *cmd, void *dummy, const char } ap_threads_min_free = atoi(arg); - if (ap_threads_min_free <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareServers set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - ap_threads_min_free = 1; - } - return NULL; } @@ -1246,23 +1320,6 @@ static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *ar } ap_threads_limit = atoi(arg); - if (ap_threads_limit > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxThreads of %d exceeds compile time limit " - "of %d threads,", ap_threads_limit, HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering MaxThreads to %d. To increase, please " - "see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " HARD_THREAD_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - ap_threads_limit = HARD_THREAD_LIMIT; - } - else if (ap_threads_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxThreads > 0, setting to 1"); - ap_threads_limit = 1; - } return NULL; } diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 0fe26338381..1b1d133b9f2 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -96,9 +96,8 @@ static int ap_daemons_to_start=0; static int ap_daemons_min_free=0; static int ap_daemons_max_free=0; static int ap_daemons_limit=0; /* MaxClients */ -static int server_limit = DEFAULT_SERVER_LIMIT; +static int server_limit = 0; static int first_server_limit = 0; -static int changed_limit_at_restart; static int mpm_state = AP_MPMQ_STARTING; static ap_pod_t *pod; @@ -900,14 +899,6 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_log_pid(pconf, ap_pid_fname); - first_server_limit = server_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - /* Initialize cross-process accept lock */ ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, ap_server_root_relative(_pconf, ap_lock_fname), @@ -1245,20 +1236,31 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) */ static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { + static int restart_num = 0; + int startup = 0; + int level_flags = 0; apr_status_t rv; pconf = p; ap_server_conf = s; + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + startup = 1; + level_flags |= APLOG_STARTUP; + } + if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); + 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|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); + ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, + (startup ? NULL : s), + "could not open pipe-of-death"); return DONE; } return OK; @@ -1307,6 +1309,7 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp 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_lock_fname = DEFAULT_LOCKFILE; @@ -1321,9 +1324,133 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp return OK; } +static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + static int restart_num = 0; + int startup = 0; + apr_status_t rv; + + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + 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 (!first_server_limit) { + first_server_limit = server_limit; + } + else if (server_limit != 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, first_server_limit); + server_limit = 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 ap_mpm_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 ap_mpm_run() */ + + return OK; +} + static void prefork_hooks(apr_pool_t *p) { - /* The prefork open_logs phase must run before the core's, or stderr + /* 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. */ @@ -1333,11 +1460,12 @@ static void prefork_hooks(apr_pool_t *p) (void) set42sig(); #endif - ap_hook_open_logs(prefork_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); + 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); } static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) @@ -1359,16 +1487,6 @@ static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char } ap_daemons_min_free = atoi(arg); - if (ap_daemons_min_free <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareServers set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - ap_daemons_min_free = 1; - } - return NULL; } @@ -1391,62 +1509,17 @@ static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg } ap_daemons_limit = atoi(arg); - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d exceeds ServerLimit value " - "of %d servers,", ap_daemons_limit, server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the ServerLimit", server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } return NULL; } static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) { - int tmp_server_limit; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } + server_limit = atoi(arg); return NULL; } diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index 03985354ce4..80d38beacc5 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -62,9 +62,8 @@ DWORD my_pid; int ap_threads_per_child = 0; int use_acceptex = 1; -static int thread_limit = DEFAULT_THREAD_LIMIT; +static int thread_limit = 0; static int first_thread_limit = 0; -static int changed_limit_at_restart; int winnt_mpm_state = AP_MPMQ_STARTING; /* ap_my_generation are used by the scoreboard code */ @@ -119,62 +118,16 @@ static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg } ap_threads_per_child = atoi(arg); - if (ap_threads_per_child > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d threads,", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } return NULL; } static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) { - int tmp_thread_limit; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d threads,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } + thread_limit = atoi(arg); return NULL; } static const char *set_disable_acceptex(cmd_parms *cmd, void *dummy, char *arg) @@ -1398,6 +1351,7 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt } ap_listen_pre_config(); + thread_limit = DEFAULT_THREAD_LIMIT; ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; ap_pid_fname = DEFAULT_PIDLOG; ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; @@ -1415,6 +1369,100 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt return OK; } +static int winnt_check_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec* s) +{ + int is_parent; + static int restart_num = 0; + int startup = 0; + + /* We want this only in the parent and only the first time around */ + is_parent = (parent_pid == my_pid); + if (is_parent && restart_num++ == 0) { + startup = 1; + } + + if (thread_limit > MAX_THREAD_LIMIT) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadLimit of %d exceeds compile-time " + "limit of", thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + MAX_THREAD_LIMIT, MAX_THREAD_LIMIT); + } else if (is_parent) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadLimit of %d exceeds compile-time limit " + "of %d, decreasing to match", + thread_limit, MAX_THREAD_LIMIT); + } + thread_limit = MAX_THREAD_LIMIT; + } + else if (thread_limit < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadLimit of %d not allowed, " + "increasing to 1.", thread_limit); + } else if (is_parent) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadLimit of %d not allowed, increasing to 1", + thread_limit); + } + thread_limit = 1; + } + + /* You cannot change ThreadLimit across a restart; ignore + * any such attempts. + */ + if (!first_thread_limit) { + first_thread_limit = thread_limit; + } + else if (thread_limit != first_thread_limit) { + /* Don't need a startup console version here */ + if (is_parent) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "changing ThreadLimit to %d from original value " + "of %d not allowed during restart", + thread_limit, first_thread_limit); + } + thread_limit = first_thread_limit; + } + + if (ap_threads_per_child > thread_limit) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " + "of", ap_threads_per_child); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + thread_limit, thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " To increase, please see the ThreadLimit " + "directive."); + } else if (is_parent) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadsPerChild of %d exceeds ThreadLimit " + "of %d, decreasing to match", + ap_threads_per_child, thread_limit); + } + ap_threads_per_child = thread_limit; + } + else if (ap_threads_per_child < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadsPerChild of %d not allowed, " + "increasing to 1.", ap_threads_per_child); + } else if (is_parent) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadsPerChild of %d not allowed, increasing to 1", + ap_threads_per_child); + } + ap_threads_per_child = 1; + } + + return OK; +} + static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec* s) { static int restart_num = 0; @@ -1627,17 +1675,6 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) { static int restart = 0; /* Default is "not a restart" */ - if (!restart) { - first_thread_limit = thread_limit; - } - - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ap_server_conf, - "WARNING: Attempt to change ThreadLimit ignored " - "during restart"); - changed_limit_at_restart = 0; - } - /* ### If non-graceful restarts are ever introduced - we need to rerun * the pre_mpm hook on subsequent non-graceful restarts. But Win32 * has only graceful style restarts - and we need this hook to act @@ -1698,16 +1735,17 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) static void winnt_hooks(apr_pool_t *p) { - /* The prefork open_logs phase must run before the core's, or stderr + /* 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_pre_config(winnt_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_config(winnt_check_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(winnt_post_config, NULL, NULL, 0); ap_hook_child_init(winnt_child_init, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_open_logs(winnt_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); + ap_hook_open_logs(winnt_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST); } AP_MODULE_DECLARE_DATA module mpm_winnt_module = { diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index d7cf048263b..93ac863c48d 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -119,11 +119,11 @@ static int ap_daemons_to_start = 0; static int min_spare_threads = 0; static int max_spare_threads = 0; static int ap_daemons_limit = 0; -static int server_limit = DEFAULT_SERVER_LIMIT; +static int max_clients = 0; +static int server_limit = 0; static int first_server_limit = 0; -static int thread_limit = DEFAULT_THREAD_LIMIT; +static int thread_limit = 0; static int first_thread_limit = 0; -static int changed_limit_at_restart; static int dying = 0; static int workers_may_exit = 0; static int start_thread_may_exit = 0; @@ -1666,15 +1666,6 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_log_pid(pconf, ap_pid_fname); - first_server_limit = server_limit; - first_thread_limit = thread_limit; - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, - "WARNING: Attempt to change ServerLimit or ThreadLimit " - "ignored during restart"); - changed_limit_at_restart = 0; - } - /* Initialize cross-process accept lock */ ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, ap_server_root_relative(_pconf, ap_lock_fname), @@ -1724,9 +1715,10 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) /* 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 + * rapidly... and for each one that exits we may start a new one, until + * there are at least min_spare_threads idle threads, counting across + * all children. But we may be permitted to start more children 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; @@ -1893,21 +1885,32 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) */ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { + static int restart_num = 0; + int startup = 0; + int level_flags = 0; apr_status_t rv; pconf = p; ap_server_conf = s; + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + startup = 1; + level_flags |= APLOG_STARTUP; + } + if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); + ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0, + (startup ? NULL : s), + "no listening sockets available, shutting down"); return DONE; } if (!one_process) { if ((rv = ap_mpm_pod_open(pconf, &pod))) { - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, - "Could not open pipe-of-death."); + ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, + (startup ? NULL : s), + "could not open pipe-of-death"); return DONE; } } @@ -1919,48 +1922,10 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, { static int restart_num = 0; int no_detach, debug, foreground; - ap_directive_t *pdir; - ap_directive_t *max_clients = NULL; apr_status_t rv; mpm_state = AP_MPMQ_STARTING; - /* make sure that "ThreadsPerChild" gets set before "MaxClients" */ - for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) { - if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) { - if (!max_clients) { - break; /* we're in the clear, got ThreadsPerChild first */ - } - else { - /* now to swap the data */ - ap_directive_t temp; - - temp.directive = pdir->directive; - temp.args = pdir->args; - /* Make sure you don't change 'next', or you may get loops! */ - /* XXX: first_child, parent, and data can never be set - * for these directives, right? -aaron */ - temp.filename = pdir->filename; - temp.line_num = pdir->line_num; - - pdir->directive = max_clients->directive; - pdir->args = max_clients->args; - pdir->filename = max_clients->filename; - pdir->line_num = max_clients->line_num; - - max_clients->directive = temp.directive; - max_clients->args = temp.args; - max_clients->filename = temp.filename; - max_clients->line_num = temp.line_num; - break; - } - } - else if (!max_clients - && strncasecmp(pdir->directive, "MaxClients", 10) == 0) { - max_clients = pdir; - } - } - debug = ap_exists_config_define("DEBUG"); if (debug) { @@ -1994,8 +1959,11 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, ap_daemons_to_start = DEFAULT_START_DAEMON; min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; + server_limit = DEFAULT_SERVER_LIMIT; + thread_limit = DEFAULT_THREAD_LIMIT; ap_daemons_limit = server_limit; ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; + max_clients = ap_daemons_limit * ap_threads_per_child; ap_pid_fname = DEFAULT_PIDLOG; ap_lock_fname = DEFAULT_LOCKFILE; ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; @@ -2009,20 +1977,258 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, return OK; } +static int worker_check_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + static int restart_num = 0; + int startup = 0; + apr_status_t rv; + + /* the reverse of pre_config, we want this only the first time around */ + if (restart_num++ == 0) { + 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 (!first_server_limit) { + first_server_limit = server_limit; + } + else if (server_limit != 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, first_server_limit); + server_limit = first_server_limit; + } + + if (thread_limit > MAX_THREAD_LIMIT) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadLimit of %d exceeds compile-time " + "limit of", thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + MAX_THREAD_LIMIT, MAX_THREAD_LIMIT); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadLimit of %d exceeds compile-time limit " + "of %d, decreasing to match", + thread_limit, MAX_THREAD_LIMIT); + } + thread_limit = MAX_THREAD_LIMIT; + } + else if (thread_limit < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadLimit of %d not allowed, " + "increasing to 1.", thread_limit); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadLimit of %d not allowed, increasing to 1", + thread_limit); + } + thread_limit = 1; + } + + /* you cannot change ThreadLimit across a restart; ignore + * any such attempts + */ + if (!first_thread_limit) { + first_thread_limit = thread_limit; + } + else if (thread_limit != first_thread_limit) { + /* don't need a startup console version here */ + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "changing ThreadLimit to %d from original value of %d " + "not allowed during restart", + thread_limit, first_thread_limit); + thread_limit = first_thread_limit; + } + + if (ap_threads_per_child > thread_limit) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " + "of", ap_threads_per_child); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d threads, decreasing to %d.", + thread_limit, thread_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " To increase, please see the ThreadLimit " + "directive."); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadsPerChild of %d exceeds ThreadLimit " + "of %d, decreasing to match", + ap_threads_per_child, thread_limit); + } + ap_threads_per_child = thread_limit; + } + else if (ap_threads_per_child < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: ThreadsPerChild of %d not allowed, " + "increasing to 1.", ap_threads_per_child); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "ThreadsPerChild of %d not allowed, increasing to 1", + ap_threads_per_child); + } + ap_threads_per_child = 1; + } + + if (max_clients < ap_threads_per_child) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d is less than " + "ThreadsPerChild of", max_clients); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " %d, increasing to %d. MaxClients must be at " + "least as large", + ap_threads_per_child, ap_threads_per_child); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " as the number of threads in a single server."); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxClients of %d is less than ThreadsPerChild " + "of %d, increasing to match", + max_clients, ap_threads_per_child); + } + max_clients = ap_threads_per_child; + } + + ap_daemons_limit = max_clients / ap_threads_per_child; + + if (max_clients % ap_threads_per_child) { + int tmp_max_clients = ap_daemons_limit * ap_threads_per_child; + + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d is not an integer " + "multiple of", max_clients); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " ThreadsPerChild of %d, decreasing to nearest " + "multiple %d,", ap_threads_per_child, + tmp_max_clients); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " for a maximum of %d servers.", + ap_daemons_limit); + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "MaxClients of %d is not an integer multiple of " + "ThreadsPerChild of %d, decreasing to nearest " + "multiple %d", max_clients, ap_threads_per_child, + tmp_max_clients); + } + max_clients = tmp_max_clients; + } + + if (ap_daemons_limit > server_limit) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MaxClients of %d would require %d " + "servers and ", max_clients, ap_daemons_limit); + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + " would exceed ServerLimit of %d, decreasing to %d.", + server_limit, server_limit * ap_threads_per_child); + 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 would require %d servers and " + "exceed ServerLimit of %d, decreasing to %d", + max_clients, ap_daemons_limit, server_limit, + server_limit * ap_threads_per_child); + } + ap_daemons_limit = server_limit; + } + + /* ap_daemons_to_start > ap_daemons_limit checked in ap_mpm_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 (min_spare_threads < 1) { + if (startup) { + ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, + "WARNING: MinSpareThreads of %d not allowed, " + "increasing to 1", min_spare_threads); + 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, + "MinSpareThreads of %d not allowed, increasing to 1", + min_spare_threads); + } + min_spare_threads = 1; + } + + /* max_spare_threads < min_spare_threads + ap_threads_per_child + * checked in ap_mpm_run() + */ + + return OK; +} + static void worker_hooks(apr_pool_t *p) { - /* The worker open_logs phase must run before the core's, or stderr + /* 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}; one_process = 0; - ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); + ap_hook_open_logs(worker_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(worker_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); + ap_hook_check_config(worker_check_config, NULL, NULL, APR_HOOK_MIDDLE); } static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, @@ -2046,16 +2252,6 @@ static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, } min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - return NULL; } @@ -2074,60 +2270,12 @@ static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg) { - int max_clients; const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - /* It is ok to use ap_threads_per_child here because we are - * sure that it gets set before MaxClients in the pre_config stage. */ max_clients = atoi(arg); - if (max_clients < ap_threads_per_child) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) must be at least as large", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " as ThreadsPerChild (%d). Automatically", - ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " increasing MaxClients to %d.", - ap_threads_per_child); - max_clients = ap_threads_per_child; - } - ap_daemons_limit = max_clients / ap_threads_per_child; - if ((max_clients > 0) && (max_clients % ap_threads_per_child)) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients (%d) is not an integer multiple", - max_clients); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " of ThreadsPerChild (%d), lowering MaxClients to %d", - ap_threads_per_child, - ap_daemons_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " for a maximum of %d child processes,", - ap_daemons_limit); - max_clients = ap_daemons_limit * ap_threads_per_child; - } - if (ap_daemons_limit > server_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: MaxClients of %d would require %d servers,", - max_clients, ap_daemons_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " and would exceed the ServerLimit value of %d.", - server_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " Automatically lowering MaxClients to %d. To increase,", - server_limit * ap_threads_per_child); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " please see the ServerLimit directive."); - ap_daemons_limit = server_limit; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } return NULL; } @@ -2140,103 +2288,28 @@ static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, } ap_threads_per_child = atoi(arg); - if (ap_threads_per_child > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "threads, lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } return NULL; } static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) { - int tmp_server_limit; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - tmp_server_limit = atoi(arg); - /* you cannot change ServerLimit across a restart; ignore - * any such attempts - */ - if (first_server_limit && - tmp_server_limit != server_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - server_limit = tmp_server_limit; - - if (server_limit > MAX_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ServerLimit of %d exceeds compile time limit " - "of %d servers,", server_limit, MAX_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); - server_limit = MAX_SERVER_LIMIT; - } - else if (server_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ServerLimit > 0, setting to 1"); - server_limit = 1; - } + server_limit = atoi(arg); return NULL; } static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) { - int tmp_thread_limit; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d servers,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } + thread_limit = atoi(arg); return NULL; }