]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
MPMs: cap idle_spawn_rate to MAX_SPAWN_RATE.
authorYann Ylavic <ylavic@apache.org>
Mon, 20 Sep 2021 14:27:42 +0000 (14:27 +0000)
committerYann Ylavic <ylavic@apache.org>
Mon, 20 Sep 2021 14:27:42 +0000 (14:27 +0000)
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

server/mpm/event/event.c
server/mpm/netware/mpm_netware.c
server/mpm/prefork/prefork.c
server/mpm/worker/worker.c

index 2c2cd83a85b837d85030fa4621f8c6a92856e947..bdaf93e2f711393bf40d99c2aab47580d748561d 100644 (file)
@@ -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
index fa26630d4d31bcb8cc051a141becc0ec84acf418..2f499c70c1c948574977766d630e1b3bf7bdbe3d 100644 (file)
@@ -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;
+                }
             }
         }
     }
index 20241cf6c65c5cecd6a7e5ba64b7bc213d68784e..dfbc175585cea87404caaf41d5aa1afb4457ea34 100644 (file)
@@ -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;
+                }
             }
         }
     }
index c3f2be6f6a4517918338c9b64ba0582cdaa57ab5..12708c43b6dacb58803cac9eee1893136783fefd 100644 (file)
@@ -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