From c99b8fb34f26c1437b7bfdd0666cd71fee4c309a Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 11 Nov 2008 18:35:48 +0000 Subject: [PATCH] pull back change from apr 1.3.0 " *) Rework the WIN32 CV code to signal the condition only if one or more threads are blocked on the condition variable. If no threads are waiting on the condition variable, nothing happens. The change also eliminates the thundering-herd problem of the manual-reset event, which (theoretically) wakes up all threads waiting on. Now the behavior of the CV's should be the same on Unix and win32 platforms. PR 42305. [Davi Arnaut] " git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@10334 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- .../include/arch/win32/apr_arch_thread_cond.h | 9 +- libs/apr/locks/win32/thread_cond.c | 142 +++++++++++------- src/switch_time.c | 2 - 3 files changed, 94 insertions(+), 59 deletions(-) diff --git a/libs/apr/include/arch/win32/apr_arch_thread_cond.h b/libs/apr/include/arch/win32/apr_arch_thread_cond.h index 840949c26a..c7f69f8064 100644 --- a/libs/apr/include/arch/win32/apr_arch_thread_cond.h +++ b/libs/apr/include/arch/win32/apr_arch_thread_cond.h @@ -21,10 +21,11 @@ struct apr_thread_cond_t { apr_pool_t *pool; - HANDLE event; - int signal_all; - int num_waiting; - int signalled; + HANDLE semaphore; + CRITICAL_SECTION csection; + unsigned long num_waiting; + unsigned long num_wake; + unsigned long generation; }; #endif /* THREAD_COND_H */ diff --git a/libs/apr/locks/win32/thread_cond.c b/libs/apr/locks/win32/thread_cond.c index 30d2c4a2bc..60286e542d 100644 --- a/libs/apr/locks/win32/thread_cond.c +++ b/libs/apr/locks/win32/thread_cond.c @@ -18,67 +18,98 @@ #include "apr_private.h" #include "apr_general.h" #include "apr_strings.h" -#include "win32/apr_arch_thread_mutex.h" -#include "win32/apr_arch_thread_cond.h" +#include "apr_arch_thread_mutex.h" +#include "apr_arch_thread_cond.h" #include "apr_portable.h" +#include + static apr_status_t thread_cond_cleanup(void *data) { apr_thread_cond_t *cond = data; - CloseHandle(cond->event); + CloseHandle(cond->semaphore); + DeleteCriticalSection(&cond->csection); return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, apr_pool_t *pool) { - *cond = apr_palloc(pool, sizeof(**cond)); - (*cond)->pool = pool; - (*cond)->event = CreateEvent(NULL, TRUE, FALSE, NULL); - (*cond)->signal_all = 0; - (*cond)->num_waiting = 0; + apr_thread_cond_t *cv; - apr_pool_cleanup_register(pool, *cond, thread_cond_cleanup, - apr_pool_cleanup_null); + cv = apr_pcalloc(pool, sizeof(**cond)); + if (cv == NULL) { + return APR_ENOMEM; + } + + cv->semaphore = CreateSemaphore(NULL, 0, LONG_MAX, NULL); + if (cv->semaphore == NULL) { + return apr_get_os_error(); + } + + *cond = cv; + cv->pool = pool; + InitializeCriticalSection(&cv->csection); + apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup, + apr_pool_cleanup_null); return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) +{ + return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); +} + static APR_INLINE apr_status_t _thread_cond_timedwait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex, DWORD timeout_ms ) { DWORD res; + apr_status_t rv; + unsigned int wake = 0; + unsigned long generation; - while (1) { - cond->num_waiting++; + EnterCriticalSection(&cond->csection); + cond->num_waiting++; + generation = cond->generation; + LeaveCriticalSection(&cond->csection); - apr_thread_mutex_unlock(mutex); - res = WaitForSingleObject(cond->event, timeout_ms); - apr_thread_mutex_lock(mutex); - cond->num_waiting--; - if (res != WAIT_OBJECT_0) { - apr_status_t rv = apr_get_os_error(); - if (res == WAIT_TIMEOUT) { - return APR_TIMEUP; + apr_thread_mutex_unlock(mutex); + + do { + res = WaitForSingleObject(cond->semaphore, timeout_ms); + + EnterCriticalSection(&cond->csection); + + if (cond->num_wake) { + if (cond->generation != generation) { + cond->num_wake--; + cond->num_waiting--; + rv = APR_SUCCESS; + break; + } else { + wake = 1; } - return apr_get_os_error(); } - if (cond->signal_all) { - if (cond->num_waiting == 0) { - cond->signal_all = 0; - cond->signalled = 0; - ResetEvent(cond->event); - } + else if (res != WAIT_OBJECT_0) { + cond->num_waiting--; + rv = APR_TIMEUP; break; } - else if (cond->signalled) { - cond->signalled = 0; - ResetEvent(cond->event); - break; + + LeaveCriticalSection(&cond->csection); + + if (wake) { + wake = 0; + ReleaseSemaphore(cond->semaphore, 1, NULL); } - } - return APR_SUCCESS; + } while (1); + + LeaveCriticalSection(&cond->csection); + apr_thread_mutex_lock(mutex); + + return rv; } APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, @@ -98,35 +129,40 @@ APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) { - apr_status_t rv = APR_SUCCESS; - DWORD res; + unsigned int wake = 0; - cond->signalled = 1; - res = SetEvent(cond->event); - if (res == 0) { - rv = apr_get_os_error(); + EnterCriticalSection(&cond->csection); + if (cond->num_waiting > cond->num_wake) { + wake = 1; + cond->num_wake++; + cond->generation++; } - return rv; + LeaveCriticalSection(&cond->csection); + + if (wake) { + ReleaseSemaphore(cond->semaphore, 1, NULL); + } + + return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) { - apr_status_t rv = APR_SUCCESS; - DWORD res; + unsigned long num_wake = 0; - cond->signalled = 1; - cond->signal_all = 1; - res = SetEvent(cond->event); - if (res == 0) { - rv = apr_get_os_error(); + EnterCriticalSection(&cond->csection); + if (cond->num_waiting > cond->num_wake) { + num_wake = cond->num_waiting - cond->num_wake; + cond->num_wake = cond->num_waiting; + cond->generation++; } - return rv; -} + LeaveCriticalSection(&cond->csection); -APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) -{ - return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); + if (num_wake) { + ReleaseSemaphore(cond->semaphore, num_wake, NULL); + } + + return APR_SUCCESS; } APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) - diff --git a/src/switch_time.c b/src/switch_time.c index 3f8eec5c0f..9e4e0df0b8 100644 --- a/src/switch_time.c +++ b/src/switch_time.c @@ -408,9 +408,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime) switch_mutex_init(&TIMER_MATRIX[1].mutex, SWITCH_MUTEX_NESTED, module_pool); switch_thread_cond_create(&TIMER_MATRIX[1].cond, module_pool); -#ifndef WIN32 globals.use_cond_yield = globals.RUNNING == 1; -#endif while (globals.RUNNING == 1) { runtime.reference += STEP_MIC;