win32: resolve condition methods at runtime
authorLars Op den Kamp <lars@opdenkamp.eu>
Thu, 2 Feb 2012 00:58:14 +0000 (01:58 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 2 Feb 2012 01:25:00 +0000 (02:25 +0100)
src/lib/platform/posix/os-threads.h
src/lib/platform/threads/mutex.h
src/lib/platform/windows/os-threads.h

index c49260ca68d88f1153bb9106237059edb2d8eeb7..f417b12d2901dec4d3a6fe11c47ada5ddf1a0a40 100644 (file)
@@ -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;
+  };
 }
index a203fbf110a61ebc7b070c573877b720d4e5917c..d44c0f1953b532da1cfd81a22eaac01bf0fe4048 100644 (file)
@@ -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;
   };
 }
index df1af39e5f0c82e6daa918eb8b99fefafd515853..52bd4bc11ab946b3018bd522b01b64b0ace7cd9b 100644 (file)
@@ -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;
+  };
 }