From: William A. Rowe Jr Date: Mon, 15 Oct 2007 22:49:57 +0000 (+0000) Subject: mpm_winnt: Eliminate wait_for_many_objects. Allows the clean X-Git-Tag: 2.2.7~301 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=259c9321e0b308bdbe65992d08b4237a0d77d5df;p=thirdparty%2Fapache%2Fhttpd.git mpm_winnt: Eliminate wait_for_many_objects. Allows the clean shutdown of the server when the MaxClients is higher then 257, in a more responsive manner [Mladen Turk, William Rowe] Per Mladen's +1, and that it's addressed all of Roy's concerns with Mladen's original patch. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@584958 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index f9b82d270d6..713f595e094 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ - -*- coding: utf-8 -*- + -*- coding: utf-8 -*- Changes with Apache 2.2.7 + *) mpm_winnt: Eliminate wait_for_many_objects. Allows the clean + shutdown of the server when the MaxClients is higher then 257, + in a more responsive manner [Mladen Turk, William Rowe] + *) mod_proxy_http: Remove Warning headers with wrong date PR 16138 [Nick Kew] diff --git a/STATUS b/STATUS index d2b065eda10..471f6848ecf 100644 --- a/STATUS +++ b/STATUS @@ -83,16 +83,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] - * mpm_winnt: Eliminate wait_for_many_objects. Allows the clean - shutdown of the server when the MaxClients is higher then 257, - in a more responsive manner. - Trunk version of patch: - http://svn.apache.org/viewvc?view=rev&revision=573103 - http://svn.apache.org/viewvc?view=rev&revision=573105 - 2.2.x version of patch: - http://people.apache.org/~wrowe/mpm_winnt_shutdown-2.2.patch - +1: wrowe, mturk - * mod_authn_dbd: Export any additional columns queried in the SQL select into the environment with the name AUTHENTICATE_. This brings mod_authn_dbd behaviour in line with mod_authnz_ldap. diff --git a/os/win32/os.h b/os/win32/os.h index ff7dc0089b6..8b9f8acb032 100644 --- a/os/win32/os.h +++ b/os/win32/os.h @@ -87,9 +87,6 @@ FARPROC ap_load_dll_func(ap_dlltoken_e fnLib, char* fnName, int ordinal); PSECURITY_ATTRIBUTES GetNullACL(); void CleanNullACL(void *sa); -DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles, - DWORD dwSeconds); - int set_listeners_noninheritable(apr_pool_t *p); diff --git a/os/win32/util_win32.c b/os/win32/util_win32.c index a0bb7fd7de1..ab96ff11367 100644 --- a/os/win32/util_win32.c +++ b/os/win32/util_win32.c @@ -145,42 +145,3 @@ void CleanNullACL(void *sa) LocalFree(sa); } } - - -/* - * The Win32 call WaitForMultipleObjects will only allow you to wait for - * a maximum of MAXIMUM_WAIT_OBJECTS (current 64). Since the threading - * model in the multithreaded version of apache wants to use this call, - * we are restricted to a maximum of 64 threads. This is a simplistic - * routine that will increase this size. - */ -DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles, - DWORD dwSeconds) -{ - time_t tStopTime; - DWORD dwRet = WAIT_TIMEOUT; - DWORD dwIndex=0; - BOOL bFirst = TRUE; - - tStopTime = time(NULL) + dwSeconds; - - do { - if (!bFirst) - Sleep(1000); - else - bFirst = FALSE; - - for (dwIndex = 0; dwIndex * MAXIMUM_WAIT_OBJECTS < nCount; dwIndex++) { - dwRet = WaitForMultipleObjects( - min(MAXIMUM_WAIT_OBJECTS, nCount - (dwIndex * MAXIMUM_WAIT_OBJECTS)), - lpHandles + (dwIndex * MAXIMUM_WAIT_OBJECTS), - 0, 0); - - if (dwRet != WAIT_TIMEOUT) { - break; - } - } - } while((time(NULL) < tStopTime) && (dwRet == WAIT_TIMEOUT)); - - return dwRet; -} diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index 8996bfd85fa..4fcad5c34a0 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -863,14 +863,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"); @@ -1109,21 +1110,71 @@ 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_TIMEOUT) { - rv = rv - WAIT_OBJECT_0; - 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 */ if (threads_created) { ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf,