From: Yann Ylavic Date: Mon, 20 Sep 2021 14:27:42 +0000 (+0000) Subject: MPMs: cap idle_spawn_rate to MAX_SPAWN_RATE. X-Git-Tag: 2.5.0-alpha2-ci-test-only~802 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=266ae085c3422684c7accee96bb79cc0fd610b64;p=thirdparty%2Fapache%2Fhttpd.git MPMs: cap idle_spawn_rate to MAX_SPAWN_RATE. idle_spawn_rate *= 2 can go above MAX_SPAWN_RATE at some point, and it's not enough for MAX_SPAWN_RATE to be a power of two for MPMs event and worker since idle_spawn_rate is per bucket (num_buckets is not necessarily a power of two). Let's cap on the other MPMs too should MAX_SPAWN_RATE change in the future. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1893471 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 2c2cd83a85b..bdaf93e2f71 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -435,13 +435,15 @@ typedef struct event_retained_data { * reset only when a cycle goes by without the need to spawn. */ int *idle_spawn_rate; -#ifndef MAX_SPAWN_RATE -#define MAX_SPAWN_RATE (32) -#endif int hold_off_on_exponential_spawning; } event_retained_data; static event_retained_data *retained; +#ifndef MAX_SPAWN_RATE +#define MAX_SPAWN_RATE 32 +#endif +static int max_spawn_rate_per_bucket = MAX_SPAWN_RATE / 1; + struct event_srv_cfg_s { struct timeout_queue *wc_q, *ka_q; @@ -3277,8 +3279,12 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) --retained->hold_off_on_exponential_spawning; } else if (retained->idle_spawn_rate[child_bucket] - < MAX_SPAWN_RATE / num_buckets) { - retained->idle_spawn_rate[child_bucket] *= 2; + < max_spawn_rate_per_bucket) { + int new_rate = retained->idle_spawn_rate[child_bucket] * 2; + if (new_rate > max_spawn_rate_per_bucket) { + new_rate = max_spawn_rate_per_bucket; + } + retained->idle_spawn_rate[child_bucket] = new_rate; } } } @@ -3538,6 +3544,11 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) if (max_spare_threads < min_spare_threads + (threads_per_child + 1) * num_buckets) max_spare_threads = min_spare_threads + (threads_per_child + 1) * num_buckets; + max_spawn_rate_per_bucket = (MAX_SPAWN_RATE + num_buckets - 1) / num_buckets; + if (max_spawn_rate_per_bucket < 1) { + max_spawn_rate_per_bucket = 1; + } + /* If we're doing a graceful_restart then we're going to see a lot * of children exiting immediately when we get into the main loop * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty diff --git a/server/mpm/netware/mpm_netware.c b/server/mpm/netware/mpm_netware.c index fa26630d4d3..2f499c70c1c 100644 --- a/server/mpm/netware/mpm_netware.c +++ b/server/mpm/netware/mpm_netware.c @@ -709,6 +709,9 @@ static void perform_idle_server_maintenance(apr_pool_t *p) } else if (idle_spawn_rate < MAX_SPAWN_RATE) { idle_spawn_rate *= 2; + if (idle_spawn_rate > MAX_SPAWN_RATE) { + idle_spawn_rate = MAX_SPAWN_RATE; + } } } } diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 20241cf6c65..dfbc175585c 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -879,6 +879,9 @@ static void perform_idle_server_maintenance(apr_pool_t *p) } else if (retained->idle_spawn_rate < MAX_SPAWN_RATE) { retained->idle_spawn_rate *= 2; + if (retained->idle_spawn_rate > MAX_SPAWN_RATE) { + retained->idle_spawn_rate = MAX_SPAWN_RATE; + } } } } diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index c3f2be6f6a4..12708c43b6d 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -173,13 +173,15 @@ typedef struct worker_retained_data { * reset only when a cycle goes by without the need to spawn. */ int *idle_spawn_rate; -#ifndef MAX_SPAWN_RATE -#define MAX_SPAWN_RATE (32) -#endif int hold_off_on_exponential_spawning; } worker_retained_data; static worker_retained_data *retained; +#ifndef MAX_SPAWN_RATE +#define MAX_SPAWN_RATE 32 +#endif +static int max_spawn_rate_per_bucket = MAX_SPAWN_RATE / 1; + #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) /* The structure used to pass unique initialization info to each thread */ @@ -1444,7 +1446,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) if (any_dead_threads && bucket == child_bucket && totally_free_length < retained->idle_spawn_rate[child_bucket] - && free_length < MAX_SPAWN_RATE / num_buckets + && free_length < max_spawn_rate_per_bucket && (!ps->pid /* no process in the slot */ || ps->quiescing)) { /* or at least one is going away */ if (all_dead_threads) { @@ -1563,8 +1565,12 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) --retained->hold_off_on_exponential_spawning; } else if (retained->idle_spawn_rate[child_bucket] - < MAX_SPAWN_RATE / num_buckets) { - retained->idle_spawn_rate[child_bucket] *= 2; + < max_spawn_rate_per_bucket) { + int new_rate = retained->idle_spawn_rate[child_bucket] * 2; + if (new_rate > max_spawn_rate_per_bucket) { + new_rate = max_spawn_rate_per_bucket; + } + retained->idle_spawn_rate[child_bucket] = new_rate; } } } @@ -1840,6 +1846,11 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) if (max_spare_threads < min_spare_threads + (threads_per_child + 1) * num_buckets) max_spare_threads = min_spare_threads + (threads_per_child + 1) * num_buckets; + max_spawn_rate_per_bucket = (MAX_SPAWN_RATE + num_buckets - 1) / num_buckets; + if (max_spawn_rate_per_bucket < 1) { + max_spawn_rate_per_bucket = 1; + } + /* If we're doing a graceful_restart then we're going to see a lot * of children exiting immediately when we get into the main loop * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty