]> granicus.if.org Git - apache/commitdiff
Refactor releasing the child processes by eliminating the
authorWilliam A. Rowe Jr <wrowe@apache.org>
Wed, 5 Sep 2007 23:21:30 +0000 (23:21 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Wed, 5 Sep 2007 23:21:30 +0000 (23:21 +0000)
time lookup, eliminating the bogus/misimplemented function,
and introducing fairness to release any dead threads before
getting hung up on releasing longer lived threads.

Also pick up the time-to-wait from the server global timeout.

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

server/mpm/winnt/child.c

index 8cae2d5efda8e73544f25c222aafe92c9964b2db..b8e4c27e4186544e3e946c787265b68aee4b45dd 100644 (file)
@@ -897,14 +897,15 @@ void child_main(apr_pool_t *pconf)
     apr_hash_t *ht;
     ap_listen_rec *lr;
     HANDLE child_events[2];
-    int threads_created = 0;
+    HANDLE *child_handles;
     int listener_started = 0;
+    int threads_created = 0;
+    int watch_thread;
+    int time_remains;
+    int cld;
     int tid;
-    HANDLE *child_handles;
     int rv;
-    time_t end_time;
     int i;
-    int cld;
 
     apr_pool_create(&pchild, pconf);
     apr_pool_tag(pchild, "pchild");
@@ -1157,20 +1158,69 @@ void child_main(apr_pool_t *pconf)
         apr_thread_mutex_unlock(qlock);
     }
 
-    /* Give busy worker threads a chance to service their connections */
-    ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf,
-                 "Child %d: Waiting for %d worker threads to exit.", 
-                 my_pid, threads_created);
-    end_time = time(NULL) + 180;
-    while (threads_created) {
-        rv = wait_for_many_objects(threads_created, child_handles,
-                                   (DWORD)(end_time - time(NULL)));
-        if (rv != WAIT_FAILED) {
-            ap_assert((rv >= 0) && (rv < threads_created));
-            cleanup_thread(child_handles, &threads_created, rv);
+    /* Give busy threads a chance to service their connections,
+     * (no more than the global server timeout period which 
+     * we track in msec remaining).
+     */
+    watch_thread = 0;
+    time_remains = (int)(ap_server_conf->timeout / APR_TIME_C(1000));
+
+    while (threads_created)
+    {
+        int nFailsafe = MAXIMUM_WAIT_OBJECTS;
+        DWORD dwRet;
+
+        /* Every time we roll over to wait on the first group
+         * of MAXIMUM_WAIT_OBJECTS threads, take a breather,
+         * and infrequently update the error log.
+         */
+        if (watch_thread >= threads_created) {
+            if ((time_remains -= 100) < 0)
+                break;
+
+            /* Every 30 seconds give an update */
+            if ((time_remains % 30000) == 0) {
+                ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, 
+                             ap_server_conf,
+                             "Child %d: Waiting %d more seconds "
+                             "for %d worker threads to finish.", 
+                             my_pid, time_remains / 1000, threads_created);
+            }
+            /* We'll poll from the top, 10 times per second */
+            Sleep(100);
+            watch_thread = 0;
+        }
+
+        /* Fairness, on each iteration we will pick up with the thread
+         * after the one we just removed, even if it's a single thread.
+         * We don't block here.
+         */
+        dwRet = WaitForMultipleObjects(min(threads_created - watch_thread,
+                                           MAXIMUM_WAIT_OBJECTS),
+                                       child_handles + watch_thread, 0, 0);
+
+        if (dwRet == WAIT_FAILED) {
+            break;
+        }
+        if (dwRet == WAIT_TIMEOUT) {
+            /* none ready */
+            watch_thread += MAXIMUM_WAIT_OBJECTS;
             continue;
         }
-        break;
+        else if (dwRet >= WAIT_ABANDONED_0) {
+            /* We just got the ownership of the object, which
+             * should happen at most MAXIMUM_WAIT_OBJECTS times.
+             * It does NOT mean that the object is signaled.
+             */
+            if ((nFailsafe--) < 1)
+                break;
+        }
+        else {
+            watch_thread += (dwRet - WAIT_OBJECT_0);
+            if (watch_thread >= threads_created)
+                break;
+            cleanup_thread(child_handles, &threads_created, watch_thread);
+        }
     }
 
     /* Kill remaining threads off the hard way */