From 92dc4453808b49cae210e95e2d3a5b1780f7bf09 Mon Sep 17 00:00:00 2001 From: Evgeny Kotkov Date: Tue, 11 Jul 2017 16:51:09 +0000 Subject: [PATCH] mpm_winnt: Simplify the shutdown code that was waiting for multiple worker thread handles in batches. Starting from r1801636, there is no difference between ending the wait with one or multiple remaining threads. This is because we terminate the process if at least one thread is still active when we hit a timeout. Therefore, instead of making an effort to evenly distribute and batch the handles with WaitForMultipleObjects(), we could just start from one end, and wait for one thread handle at a time. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1801637 13f79535-47bb-0310-9956-ffa450edef68 --- server/mpm/winnt/child.c | 76 +++++++++------------------------------- 1 file changed, 17 insertions(+), 59 deletions(-) diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index e2d64c50c4..7cbaf81f4f 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -841,18 +841,6 @@ static DWORD __stdcall worker_main(void *thread_num_val) } -static void cleanup_thread(HANDLE *handles, int *thread_cnt, - int thread_to_clean) -{ - int i; - - CloseHandle(handles[thread_to_clean]); - for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++) - handles[i] = handles[i + 1]; - (*thread_cnt)--; -} - - /* * child_main() * Entry point for the main control thread for the child process. @@ -904,7 +892,6 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid) HANDLE *child_handles; int listener_started = 0; int threads_created = 0; - int watch_thread; int time_remains; int cld; DWORD tid; @@ -1199,64 +1186,35 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid) * (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; + HANDLE handle = child_handles[threads_created - 1]; 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, APLOGNO(00362) - "Child: Waiting %d more seconds " - "for %d worker threads to finish.", - 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) { + if (time_remains < 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, APLOGNO(00362) + "Child: Waiting %d more seconds " + "for %d worker threads to finish.", + time_remains / 1000, threads_created); } + + dwRet = WaitForSingleObject(handle, 100); + time_remains -= 100; if (dwRet == WAIT_TIMEOUT) { - /* none ready */ - watch_thread += MAXIMUM_WAIT_OBJECTS; - continue; + /* Keep waiting */ } - 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 if (dwRet == WAIT_OBJECT_0) { + CloseHandle(handle); + threads_created--; } else { - watch_thread += (dwRet - WAIT_OBJECT_0); - if (watch_thread >= threads_created) - break; - cleanup_thread(child_handles, &threads_created, watch_thread); + break; } } -- 2.50.1