From 3a590d6a4652d1c47026446dcdc44ac9852f8af3 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Thu, 2 Feb 2012 01:58:14 +0100 Subject: [PATCH] win32: resolve condition methods at runtime --- src/lib/platform/posix/os-threads.h | 45 ++++++++--- src/lib/platform/threads/mutex.h | 18 ++--- src/lib/platform/windows/os-threads.h | 110 +++++++++++++++++++++----- 3 files changed, 130 insertions(+), 43 deletions(-) diff --git a/src/lib/platform/posix/os-threads.h b/src/lib/platform/posix/os-threads.h index c49260c..f417b12 100644 --- a/src/lib/platform/posix/os-threads.h +++ b/src/lib/platform/posix/os-threads.h @@ -69,19 +69,40 @@ namespace PLATFORM #define MutexTryLock(mutex) (pthread_mutex_trylock(&mutex) == 0) #define MutexUnlock(mutex) pthread_mutex_unlock(&mutex) - typedef pthread_cond_t condition_t; - #define ConditionCreate(cond) pthread_cond_init(&cond, NULL) - #define ConditionDelete(cond) pthread_cond_destroy(&cond) - #define ConditionSignal(cond) pthread_cond_signal(&cond) - #define ConditionBroadcast(cond) pthread_cond_broadcast(&cond) - inline bool ConditionWait(condition_t &cond, mutex_t &mutex, uint32_t iTimeout) + class CConditionImpl { - sched_yield(); - if (iTimeout > 0) + public: + CConditionImpl(void) { - struct timespec timeout = GetAbsTime(iTimeout); - return (pthread_cond_timedwait(&cond, &mutex, &timeout) == 0); + pthread_cond_init(&m_condition, NULL); } - return (pthread_cond_wait(&cond, &mutex) == 0); - } + + virtual ~CConditionImpl(void) + { + pthread_cond_destroy(&m_condition); + } + + void Signal(void) + { + pthread_cond_signal(&m_condition); + } + + void Broadcast(void) + { + pthread_cond_broadcast(&m_condition); + } + + bool Wait(mutex_t &mutex, uint32_t iTimeoutMs) + { + sched_yield(); + if (iTimeout > 0) + { + struct timespec timeout = GetAbsTime(iTimeout); + return (pthread_cond_timedwait(&cond, &mutex, &timeout) == 0); + } + return (pthread_cond_wait(&cond, &mutex) == 0); + } + + pthread_cond_t m_condition; + }; } diff --git a/src/lib/platform/threads/mutex.h b/src/lib/platform/threads/mutex.h index a203fbf..d44c0f1 100644 --- a/src/lib/platform/threads/mutex.h +++ b/src/lib/platform/threads/mutex.h @@ -166,30 +166,25 @@ namespace PLATFORM class CCondition : public PreventCopy { public: - inline CCondition(void) - { - ConditionCreate(m_condition); - } - + inline CCondition(void) {} inline ~CCondition(void) { - Broadcast(); - ConditionDelete(m_condition); + m_condition.Broadcast(); } inline void Broadcast(void) { - ConditionBroadcast(m_condition); + m_condition.Broadcast(); } inline void Signal(void) { - ConditionSignal(m_condition); + m_condition.Signal(); } inline bool Wait(CMutex &mutex, uint32_t iTimeout = 0) { - return ConditionWait(m_condition, mutex.m_mutex, iTimeout); + return m_condition.Wait(mutex.m_mutex, iTimeout); } static void Sleep(uint32_t iTimeout) @@ -200,6 +195,7 @@ namespace PLATFORM w.Wait(m, iTimeout); } - condition_t m_condition; + private: + CConditionImpl m_condition; }; } diff --git a/src/lib/platform/windows/os-threads.h b/src/lib/platform/windows/os-threads.h index df1af39..52bd4bc 100644 --- a/src/lib/platform/windows/os-threads.h +++ b/src/lib/platform/windows/os-threads.h @@ -44,26 +44,96 @@ namespace PLATFORM #define MutexTryLock(mutex) (::TryEnterCriticalSection(mutex) != 0) #define MutexUnlock(mutex) ::LeaveCriticalSection(mutex) - #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) - typedef CONDITION_VARIABLE* condition_t; - #define ConditionCreate(cond) ::InitializeConditionVariable(cond = new CONDITION_VARIABLE) - #define ConditionDelete(cond) delete cond - #define ConditionSignal(cond) ::WakeConditionVariable(cond) - #define ConditionBroadcast(cond) ::WakeAllConditionVariable(cond) - #define ConditionWait(cond, mutex, timeout) (::SleepConditionVariableCS(cond, mutex, timeout <= 0 ? INFINITE : timeout) ? true : false) - #else - typedef HANDLE condition_t; - #define ConditionCreate(cond) (cond = ::CreateEvent(NULL, TRUE, FALSE, NULL)) - #define ConditionDelete(cond) ::CloseHandle(cond) - #define ConditionSignal(cond) ::SetEvent(cond) - #define ConditionBroadcast(cond) ::SetEvent(cond) - inline bool ConditionWait(condition_t cond, mutex_t mutex, uint32_t iTimeoutMsg) + // windows vista+ conditions + typedef VOID (WINAPI *ConditionArg) (CONDITION_VARIABLE*); + typedef BOOL (WINAPI *ConditionMutexArg)(CONDITION_VARIABLE*, CRITICAL_SECTION*, DWORD); + static ConditionArg g_InitializeConditionVariable; + static ConditionArg g_WakeConditionVariable; + static ConditionArg g_WakeAllConditionVariable; + static ConditionMutexArg g_SleepConditionVariableCS; + + // check whether vista+ conditions are available at runtime + static bool CheckVistaConditionFunctions(void) { - ::ResetEvent(cond); - MutexUnlock(mutex); - DWORD iWaitReturn = ::WaitForSingleObject(cond, iTimeoutMsg <= 0 ? 1000 : iTimeoutMsg); - MutexLock(mutex); - return iWaitReturn == 0; + static int iHasVistaConditionFunctions(-1); + if (iHasVistaConditionFunctions == -1) + { + HMODULE handle = GetModuleHandle("Kernel32"); + if (handle == NULL) + { + iHasVistaConditionFunctions = 0; + } + else + { + g_InitializeConditionVariable = (ConditionArg) GetProcAddress(handle,"InitializeConditionVariable"); + g_WakeConditionVariable = (ConditionArg) GetProcAddress(handle,"WakeConditionVariable"); + g_WakeAllConditionVariable = (ConditionArg) GetProcAddress(handle,"WakeAllConditionVariable"); + g_SleepConditionVariableCS = (ConditionMutexArg)GetProcAddress(handle,"SleepConditionVariableCS"); + + // 1 when everything is resolved, 0 otherwise + iHasVistaConditionFunctions = g_InitializeConditionVariable && + g_WakeConditionVariable && + g_WakeAllConditionVariable && + g_SleepConditionVariableCS ? 1 : 0; + } + } + return iHasVistaConditionFunctions == 1; } - #endif + + class CConditionImpl + { + public: + CConditionImpl(void) + { + m_bOnVista = CheckVistaConditionFunctions(); + if (m_bOnVista) + (*g_InitializeConditionVariable)(m_conditionVista = new CONDITION_VARIABLE); + else + m_conditionPreVista = ::CreateEvent(NULL, TRUE, FALSE, NULL); + } + + virtual ~CConditionImpl(void) + { + if (m_bOnVista) + delete m_conditionVista; + else + ::CloseHandle(m_conditionPreVista); + } + + void Signal(void) + { + if (m_bOnVista) + (*g_WakeConditionVariable)(m_conditionVista); + else + ::SetEvent(m_conditionPreVista); + } + + void Broadcast(void) + { + if (m_bOnVista) + (*g_WakeAllConditionVariable)(m_conditionVista); + else + ::SetEvent(m_conditionPreVista); + } + + bool Wait(mutex_t &mutex, uint32_t iTimeoutMs) + { + if (m_bOnVista) + { + return ((*g_SleepConditionVariableCS)(m_conditionVista, mutex, iTimeoutMs <= 0 ? INFINITE : iTimeoutMs) ? true : false); + } + else + { + ::ResetEvent(m_conditionPreVista); + MutexUnlock(mutex); + DWORD iWaitReturn = ::WaitForSingleObject(m_conditionPreVista, iTimeoutMs <= 0 ? 1000 : iTimeoutMs); + MutexLock(mutex); + return (iWaitReturn == 0); + } + } + + bool m_bOnVista; + CONDITION_VARIABLE *m_conditionVista; + HANDLE m_conditionPreVista; + }; } -- 2.34.1