diff options
author | Chris Darroch <chrisd@apache.org> | 2006-08-14 22:55:45 +0000 |
---|---|---|
committer | Chris Darroch <chrisd@apache.org> | 2006-08-14 22:55:45 +0000 |
commit | e69f467709a6685bd79bfdbfac922e67b5dccc8f (patch) | |
tree | cc14f49aa3c40eabb8d0bc7b94de4be6d7548015 | |
parent | 4304af36d9ab689ff7524e725b4e1305b541fd63 (diff) | |
download | httpd-e69f467709a6685bd79bfdbfac922e67b5dccc8f.tar.gz |
Introduce a check_config phase between pre_config and open_logs,
to allow modules to review interdependent configuration directive
values and adjust them while messages can still be logged to the
console.
The open_logs phase is already used somewhat for this purpose by
certain MPMs (winnt, prefork, worker, and event) but only by forcing
their functions ahead of the core ap_open_logs() function, and
since this phase runs after the ap_signal_server function during startup,
it can not be used to generate messages on the console when restarting.
Add the check_config phase to mod_info and mod_example.
Handle relevant MPM directives during this phase and format messages
for both the console and the error log, as appropriate. Bounds and sanity
checks on the values of the MPM directives are handled in sequence in
this phase instead of in the various directive handling functions, since
those functions (e.g., set_max_clients()) may not be called at all if their
directives do not appear in the configuration files, and even if they
are called, there is no guarantee that this will occur in any particular
order.
Remove from the worker and event MPMs the code in the pre_config phase
that alters the configuration node tree by re-ordering ThreadsPerChild
ahead of MaxClients. This code is effective but insufficient; for
example, if ServerLimit follows MaxClients, the test against server_limit
in set_max_clients() is invalid. (In practice, this only results in
incorrect or absent warnings on the console, because server_limit is
set to its configured value when the main loop re-runs the configuration
process.)
Prevent ap_threads_per_child from exceeding thread_limit in the
winnt, worker, and event MPMs. This situation could occur if
ThreadsPerChild was not specified in the configuration files and
ThreadLimit was set to a value smaller than DEFAULT_THREADS_PER_CHILD,
because set_threads_per_child() would never be called and therefore
its bounds check against thread_limit would not be performed.
Remove from the winnt, prefork, worker, and event MPMs the
changed_limit_at_restart flag. Set the first_server_limit and
first_thread_limit values during the first execution of the check_config
function, and use them to detect changes to ServerLimit and ThreadLimit
across restarts and issue appropriately formatted warnings. Remove the
comments about the error log being a "bit bucket"; this was true when
the code was originally committed in r92530 but that was due to a bug
fixed in r92769.
Be consistent about setting all MPM configuration directive values in the
pre_config phase.
Rephrase and reformat the console and log file messages relating to
MPM configuration directives to be consistent across all MPMs. Use
briefer messages when logging to the error log than to the console.
Update miscellaneous stale comments and messages (e.g., reference to
daemons_min_free in worker and event MPMs, "prefork open_logs" in
winnt MPM, and StartServers in netware MPM).
The winnt, netware, beos, and mpmt_os2 MPMs should be tested by developers
with access to those platforms, especially the winnt MPM, which has
unique logic with respect to distinguishing between parent and child
processes during the configuration phases.
Update the English documentation for the worker MPM's ThreadsPerChild
directive, which no longer needs to precede other MPM directives in the
configuration files if it has a non-default value. The German (.de) and
Japanese (.ja) translations should be updated by developers fluent in
those languages.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@431460 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | docs/manual/mod/worker.xml | 4 | ||||
-rw-r--r-- | include/http_config.h | 10 | ||||
-rw-r--r-- | modules/experimental/mod_example.c | 28 | ||||
-rw-r--r-- | modules/generators/mod_info.c | 1 | ||||
-rw-r--r-- | server/config.c | 6 | ||||
-rw-r--r-- | server/main.c | 13 | ||||
-rw-r--r-- | server/mpm/beos/beos.c | 135 | ||||
-rw-r--r-- | server/mpm/experimental/event/event.c | 460 | ||||
-rw-r--r-- | server/mpm/mpmt_os2/mpmt_os2.c | 58 | ||||
-rw-r--r-- | server/mpm/netware/mpm_netware.c | 111 | ||||
-rw-r--r-- | server/mpm/prefork/prefork.c | 217 | ||||
-rw-r--r-- | server/mpm/winnt/mpm_winnt.c | 162 | ||||
-rw-r--r-- | server/mpm/worker/worker.c | 461 |
14 files changed, 1071 insertions, 602 deletions
@@ -2,6 +2,13 @@ Changes with Apache 2.3.0 [Remove entries to the current 2.0 and 2.2 section below, when backported] + *) All MPMs: Introduce a check_config phase between pre_config and + open_logs, to allow modules to review interdependent configuration + directive values and adjust them while messages can still be logged + to the console. Handle relevant MPM directives during this phase + and format messages for both the console and the error log, as + appropriate. [Chris Darroch] + *) mod_proxy: don't try to use dead backend connection (PR#37770) [Olivier BOEL <ob dorrboel.com>] diff --git a/docs/manual/mod/worker.xml b/docs/manual/mod/worker.xml index 3fa1beccec..5593a5f40c 100644 --- a/docs/manual/mod/worker.xml +++ b/docs/manual/mod/worker.xml @@ -87,9 +87,7 @@ uses</a></seealso> <directive module="mpm_common">ThreadLimit</directive> is a hard limit of the number of server threads, and must be greater than or equal to the <directive - module="mpm_common">ThreadsPerChild</directive> directive. If - non-default values are specified for these directives, they - should appear before other <module>worker</module> directives.</p> + module="mpm_common">ThreadsPerChild</directive> directive.</p> <p>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 5e9fd51d0d..820a9facaf 100644 --- a/include/http_config.h +++ b/include/http_config.h @@ -985,6 +985,16 @@ 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. * @param pconf The config pool diff --git a/modules/experimental/mod_example.c b/modules/experimental/mod_example.c index 1b343fb058..f26ddf8867 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 ad2b57f32c..a999080b0c 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 8eed98b063..4e1799e744 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 e85fba6656..c968bf9cf9 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 b7e4671b06..0a46d8793e 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 2de0d27cc2..ea21b5660e 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 8fb10ce9c3..99a75c7f76 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 dd4cb3592a..f116d2b000 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 0fe2633838..1b1d133b9f 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 03985354ce..80d38beacc 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 d7cf048263..93ac863c48 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; } |