]> granicus.if.org Git - apache/commitdiff
if a child detects a resource shortage on accept(), limit the rate of fork()s
authorGreg Ames <gregames@apache.org>
Mon, 11 Feb 2002 23:20:16 +0000 (23:20 +0000)
committerGreg Ames <gregames@apache.org>
Mon, 11 Feb 2002 23:20:16 +0000 (23:20 +0000)
to 1 per second until the situation clears up.

Inspired by: Martin Kraemer

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93366 13f79535-47bb-0310-9956-ffa450edef68

include/httpd.h
server/mpm/prefork/prefork.c
server/mpm/worker/worker.c
server/mpm_common.c

index 800ea082ec0ea2e481427277dce00e0b2f14be52..254277f98460603cd54bd9a1530e51ec5b8a3179 100644 (file)
@@ -339,6 +339,12 @@ extern "C" {
 #define APEXIT_INIT            0x2
 /**  The child died during its init sequence */
 #define APEXIT_CHILDINIT       0x3
+/**  
+ *   The child exited due to a resource shortage.
+ *   The parent should limit the rate of forking until
+ *   the situation is resolved.
+ */
+#define APEXIT_CHILDSICK        0x7
 /** 
  *     A fatal error, resulting in the whole server aborting.
  *     If a child exits with this error, the parent process
index a0cf5b9238c80af6ea989683bc96c7f9606b5d4b..f7c510d9d17564ce3b3776e5a38506082264af46 100644 (file)
@@ -1037,7 +1037,7 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
     while (!restart_pending && !shutdown_pending) {
        int child_slot;
         apr_exit_why_e exitwhy;
-       int status;
+       int status, processed_status;
         /* this is a memory leak, but I'll fix it later. */
        apr_proc_t pid;
 
@@ -1048,7 +1048,8 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
         * extra child
         */
        if (pid.pid != -1) {
-            if (ap_process_child_status(&pid, exitwhy, status) == APEXIT_CHILDFATAL) {
+            processed_status = ap_process_child_status(&pid, exitwhy, status);
+            if (processed_status == APEXIT_CHILDFATAL) {
                 return 1;
             }
 
@@ -1058,7 +1059,13 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
            if (child_slot >= 0) {
                (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
                                                            (request_rec *) NULL);
-               if (remaining_children_to_start
+                if (processed_status == APEXIT_CHILDSICK) {
+                    /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
+                     * cut the fork rate to the minimum 
+                     */
+                    idle_spawn_rate = 1; 
+                }
+                else if (remaining_children_to_start
                    && child_slot < ap_daemons_limit) {
                    /* we're still doing a 1-for-1 replacement of dead
                        * children with new children
index 23733f6f93687b336920ca69e106d7796a4b7861..01607843ff8923c8beab4afd0143ad5314a7cd42 100644 (file)
@@ -169,6 +169,7 @@ static int dying = 0;
 static int workers_may_exit = 0;
 static int requests_this_child;
 static int num_listensocks = 0;
+static int resource_shortage = 0;
 static fd_queue_t *worker_queue;
 
 /* The structure used to pass unique initialization info to each thread */
@@ -675,6 +676,8 @@ static void *listener_thread(apr_thread_t *thd, void * dummy)
             rv = lr->accept_func(&csd, lr, ptrans);
 
             if (rv == APR_EGENERAL) {
+                /* E[NM]FILE, ENOMEM, etc */
+                resource_shortage = 1;
                 signal_workers();
             }
             if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex)))
@@ -965,7 +968,7 @@ static void child_main(int child_num_arg)
 
     free(threads);
 
-    clean_child_exit(0);
+    clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);
 }
 
 static int make_child(server_rec *s, int slot) 
@@ -1198,7 +1201,7 @@ static void server_main_loop(int remaining_children_to_start)
 {
     int child_slot;
     apr_exit_why_e exitwhy;
-    int status;
+    int status, processed_status;
     apr_proc_t pid;
     int i;
 
@@ -1206,8 +1209,8 @@ static void server_main_loop(int remaining_children_to_start)
         ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
         
         if (pid.pid != -1) {
-            if (ap_process_child_status(&pid, exitwhy, 
-                                        status) == APEXIT_CHILDFATAL) {
+            processed_status = ap_process_child_status(&pid, exitwhy, status);
+            if (processed_status == APEXIT_CHILDFATAL) {
                 shutdown_pending = 1;
                 child_fatal = 1;
                 return;
@@ -1221,7 +1224,11 @@ static void server_main_loop(int remaining_children_to_start)
                 
                 ap_scoreboard_image->parent[child_slot].pid = 0;
                 ap_scoreboard_image->parent[child_slot].quiescing = 0;
-                if (remaining_children_to_start
+                if (processed_status == APEXIT_CHILDSICK) {
+                    /* resource shortage, minimize the fork rate */
+                    idle_spawn_rate = 1;
+                }
+                else if (remaining_children_to_start
                     && child_slot < ap_daemons_limit) {
                     /* we're still doing a 1-for-1 replacement of dead
                      * children with new children
index 999ccf32f530e6f9f4a69aa78fca74113db74326..33642d6acfc8826b778c0ecbd6ec06894bc370f0 100644 (file)
@@ -237,15 +237,23 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status)
      * we should simply bail out.  The caller needs to
      * check for bad rc from us and exit, running any
      * appropriate cleanups.
+     *
+     * If the child died due to a resource shortage, 
+     * the parent should limit the rate of forking
      */
-    if ((APR_PROC_CHECK_EXIT(why)) &&
-        (status == APEXIT_CHILDFATAL)) {
-        ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf,
-                     "Child %" APR_OS_PROC_T_FMT
-                     " returned a Fatal error..." APR_EOL_STR
-                     "Apache is exiting!",
-                     pid->pid);
-        return APEXIT_CHILDFATAL;
+    if (APR_PROC_CHECK_EXIT(why)) {
+        if (status == APEXIT_CHILDSICK) {
+            return status;
+        }
+        if (status == APEXIT_CHILDFATAL) {
+            ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf,
+                         "Child %" APR_OS_PROC_T_FMT
+                         " returned a Fatal error..." APR_EOL_STR
+                         "Apache is exiting!",
+                         pid->pid);
+            return APEXIT_CHILDFATAL;
+        }
+        return 0;
     }
 
     if (APR_PROC_CHECK_SIGNALED(why)) {