platform: added predicate in CCondition
[deb_libcec.git] / src / lib / platform / threads / mutex.h
index 4a2ad795f86e153cc59cb3c607e443198eecc735..bb4e006e331b373dfacd585eb682e53e5f47f697 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * This file is part of the libCEC(R) library.
  *
- * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
  * libCEC(R) is an original work, containing original code.
  *
  * libCEC(R) is a trademark of Pulse-Eight Limited.
  *     http://www.pulse-eight.net/
  */
 
+#include "../os.h"
+
+#if defined(__WINDOWS__)
+#include "../windows/os-threads.h"
+#else
+#include "../posix/os-threads.h"
+#endif
+
+#include "../util/timeutils.h"
+
 namespace PLATFORM
 {
   class PreventCopy
@@ -81,8 +91,17 @@ namespace PLATFORM
 
     inline void Unlock(void)
     {
-      --m_iLockCount;
-      MutexUnlock(m_mutex);
+      if (Lock())
+      {
+        if (m_iLockCount >= 2)
+        {
+          --m_iLockCount;
+          MutexUnlock(m_mutex);
+        }
+
+        --m_iLockCount;
+        MutexUnlock(m_mutex);
+      }
     }
 
     inline bool Clear(void)
@@ -99,8 +118,8 @@ namespace PLATFORM
     }
 
   private:
-    mutex_t      m_mutex;
-    unsigned int m_iLockCount;
+    mutex_t               m_mutex;
+    volatile unsigned int m_iLockCount;
   };
 
   class CLockObject : public PreventCopy
@@ -146,33 +165,107 @@ namespace PLATFORM
     bool    m_bClearOnExit;
   };
 
-  class CCondition : public PreventCopy
+  class CTryLockObject : public PreventCopy
   {
   public:
-    inline CCondition(void)
+    inline CTryLockObject(CMutex &mutex, bool bClearOnExit = false) :
+      m_mutex(mutex),
+      m_bClearOnExit(bClearOnExit),
+      m_bIsLocked(m_mutex.TryLock())
     {
-      ConditionCreate(m_condition);
     }
 
+    inline ~CTryLockObject(void)
+    {
+      if (m_bClearOnExit)
+        Clear();
+      else if (m_bIsLocked)
+        Unlock();
+    }
+
+    inline bool TryLock(void)
+    {
+      bool bReturn = m_mutex.TryLock();
+      m_bIsLocked |= bReturn;
+      return bReturn;
+    }
+
+    inline void Unlock(void)
+    {
+      if (m_bIsLocked)
+      {
+        m_bIsLocked = false;
+        m_mutex.Unlock();
+      }
+    }
+
+    inline bool Clear(void)
+    {
+      m_bIsLocked = false;
+      return m_mutex.Clear();
+    }
+
+    inline bool Lock(void)
+    {
+      bool bReturn = m_mutex.Lock();
+      m_bIsLocked |= bReturn;
+      return bReturn;
+    }
+
+    inline bool IsLocked(void) const
+    {
+      return m_bIsLocked;
+    }
+
+  private:
+    CMutex &      m_mutex;
+    bool          m_bClearOnExit;
+    volatile bool m_bIsLocked;
+  };
+
+  class CCondition : public PreventCopy
+  {
+  public:
+    inline CCondition(void) :
+      m_bPredicate(false),
+      m_iWaitingThreads(0) {}
     inline ~CCondition(void)
     {
       Broadcast();
-      ConditionDelete(m_condition);
     }
 
-    inline void Broadcast(void)
+    void Broadcast(void)
     {
-      ConditionBroadcast(m_condition);
+      Set(true);
+      m_condition.Broadcast();
     }
 
-    inline void Signal(void)
+    void Signal(void)
     {
-      ConditionSignal(m_condition);
+      Set(false);
+      m_condition.Signal();
     }
 
-    inline bool Wait(CMutex &mutex, uint32_t iTimeout = 0)
+    bool Wait(CMutex &mutex, uint32_t iTimeout = 0)
     {
-      return ConditionWait(m_condition, mutex.m_mutex, iTimeout);
+      {
+        CLockObject lock(m_mutex);
+        ++m_iWaitingThreads;
+      }
+
+      if (iTimeout > 0)
+      {
+        CTimeout timeout(iTimeout);
+        while (!m_bPredicate && timeout.TimeLeft() > 0)
+          m_condition.Wait(mutex.m_mutex, timeout.TimeLeft());
+      }
+      else
+      {
+        while (!m_bPredicate)
+          m_condition.Wait(mutex.m_mutex, 0);
+      }
+
+      return ResetAndReturn();
     }
 
     static void Sleep(uint32_t iTimeout)
@@ -183,6 +276,27 @@ namespace PLATFORM
       w.Wait(m, iTimeout);
     }
 
-    condition_t m_condition;
+  private:
+    void Set(bool bBroadcast = false)
+    {
+      CLockObject lock(m_mutex);
+      m_bPredicate = true;
+      m_bBroadcast = bBroadcast;
+    }
+
+    bool ResetAndReturn(void)
+    {
+      CLockObject lock(m_mutex);
+      bool bReturn(m_bPredicate);
+      if (bReturn && (--m_iWaitingThreads == 0 || !m_bBroadcast))
+        m_bPredicate = false;
+      return bReturn;
+    }
+
+    CMutex         m_mutex;
+    CConditionImpl m_condition;
+    volatile bool  m_bPredicate;
+    volatile bool  m_bBroadcast;
+    unsigned int   m_iWaitingThreads;
   };
 }