]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Update timeout algorithm in free_proc_chain. Try polling the existing subprocess
authorBill Stoddard <stoddard@apache.org>
Tue, 12 Nov 2002 22:44:06 +0000 (22:44 +0000)
committerBill Stoddard <stoddard@apache.org>
Tue, 12 Nov 2002 22:44:06 +0000 (22:44 +0000)
a few times before going into a 3 second sleep. Often we find that the subprocess
will exit within milliseconds.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@97500 13f79535-47bb-0310-9956-ffa450edef68

src/CHANGES
src/main/alloc.c

index 6f84f2a0ca5b673766119f0ec00013bc572c50cb..144f3076b161cd94f388cd99cf535ec87bec88cf 100644 (file)
@@ -1,4 +1,12 @@
 Changes with Apache 1.3.28
+  *) Update timeout algorithm in free_proc_chain. If a subprocess
+     did not exit immediately, the thread would sleep for 3 seconds
+     before checking the subprocess exit status again. In a very
+     common case when the subprocess was an HTTP server CGI script,
+     the CGI script actually exited a fraction of a second into the 3
+     second sleep, which effectively limited the server to serving one 
+     CGI request every 3 seconds across a persistent connection.
+     PRs 6961, 8664 [Bill Stoddard]
 
   *) mod_setenvif: Add SERVER_ADDR special keyword to allow
      envariable setting according to the server IP address
index d479b4473d6e59e0692a1d656c006ff5405a9af8..1ffaa564c4cf7dac3cbd5dbf4158868b0c1529ec 100644 (file)
@@ -2624,15 +2624,28 @@ API_EXPORT(int) ap_bspawn_child(pool *p, int (*func) (void *, child_info *), voi
     return pid;
 }
 
+
+/* 
+ * Timing constants for killing subprocesses
+ * There is a total 3-second delay between sending a SIGINT 
+ * and sending of the final SIGKILL.
+ * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64
+ * for the exponetial timeout alogrithm.
+ */
+#define TIMEOUT_USECS    3000000
+#define TIMEOUT_INTERVAL   46875
+
 static void free_proc_chain(struct process_chain *procs)
 {
     /* Dispose of the subprocesses we've spawned off in the course of
      * whatever it was we're cleaning up now.  This may involve killing
      * some of them off...
      */
-
+    struct timeval tv;
     struct process_chain *p;
     int need_timeout = 0;
+    int timeout_interval;
+    int exit_int;
     int status;
 
     if (procs == NULL)
@@ -2694,18 +2707,49 @@ static void free_proc_chain(struct process_chain *procs)
        if ((p->kill_how == kill_after_timeout)
            || (p->kill_how == kill_only_once)) {
            /* Subprocess may be dead already.  Only need the timeout if not. */
-           if (ap_os_kill(p->pid, SIGTERM) != -1)
+           if (ap_os_kill(p->pid, SIGTERM) == -1) {
+                p->kill_how = kill_never;
+            }
+            else {
                need_timeout = 1;
+            }
        }
        else if (p->kill_how == kill_always) {
            kill(p->pid, SIGKILL);
        }
     }
 
-    /* Sleep only if we have to... */
-
-    if (need_timeout)
-       sleep(3);
+    /* Sleep only if we have to. The sleep algorithm grows
+     * by a factor of two on each iteration. TIMEOUT_INTERVAL
+     * is equal to TIMEOUT_USECS / 64.
+     */
+    if (need_timeout) {
+        timeout_interval = TIMEOUT_INTERVAL;
+        tv.tv_sec = 0;
+        tv.tv_usec = timeout_interval;
+        select(0, NULL, NULL, NULL, &tv);
+
+        do {
+            need_timeout = 0;
+            for (p = procs; p; p = p->next) {
+                if (p->kill_how == kill_after_timeout) {
+                    if (waitpid(p->pid, (int *) 0, WNOHANG | WUNTRACED) > 0)
+                        p->kill_how = kill_never;
+                    else
+                        need_timeout = 1;
+                }
+            }
+            if (need_timeout) {
+                if (timeout_interval >= TIMEOUT_USECS) {
+                    break;
+                }
+                tv.tv_sec = timeout_interval / 1000000;
+                tv.tv_usec = timeout_interval % 1000000;
+                select(0, NULL, NULL, NULL, &tv);
+                timeout_interval *= 2;
+            }
+        } while (need_timeout);
+    }
 
     /* OK, the scripts we just timed out for have had a chance to clean up
      * --- now, just get rid of them, and also clean up the system accounting
@@ -2713,7 +2757,6 @@ static void free_proc_chain(struct process_chain *procs)
      */
 
     for (p = procs; p; p = p->next) {
-
        if (p->kill_how == kill_after_timeout)
            kill(p->pid, SIGKILL);