updated copyright messages for 2013
[deb_libcec.git] / src / lib / platform / threads / mutex.h
index 4a2ad795f86e153cc59cb3c607e443198eecc735..2bd908e533ee00d2298c6c1083afdd6bcd44f3b5 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-2013 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 "lib/platform/os.h"
+
+#if defined(__WINDOWS__)
+#include "lib/platform/windows/os-threads.h"
+#else
+#include "lib/platform/posix/os-threads.h"
+#endif
+
+#include "lib/platform/util/timeutils.h"
+
 namespace PLATFORM
 {
   class PreventCopy
@@ -41,14 +51,16 @@ namespace PLATFORM
 
   private:
     inline PreventCopy(const PreventCopy &c) { *this = c; }
-    inline PreventCopy &operator=(const PreventCopy &c){ *this = c; return *this; }
+    inline PreventCopy &operator=(const PreventCopy & UNUSED(c)){ return *this; }
   };
 
-  class CCondition;
+  template <typename _Predicate>
+    class CCondition;
 
   class CMutex : public PreventCopy
   {
-    friend class CCondition;
+    template <typename _Predicate>
+      friend class CCondition;
   public:
     inline CMutex(void) :
       m_iLockCount(0)
@@ -74,15 +86,27 @@ namespace PLATFORM
 
     inline bool Lock(void)
     {
-      MutexLock(m_mutex);
-      ++m_iLockCount;
-      return true;
+      if (MutexLock(m_mutex))
+      {
+        ++m_iLockCount;
+        return true;
+      }
+      return false;
     }
 
     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 +123,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,43 +170,187 @@ 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())
+    {
+    }
+
+    inline ~CTryLockObject(void)
+    {
+      if (m_bClearOnExit)
+        Clear();
+      else if (m_bIsLocked)
+        Unlock();
+    }
+
+    inline bool TryLock(void)
     {
-      ConditionCreate(m_condition);
+      bool bReturn = m_mutex.TryLock();
+      m_bIsLocked |= bReturn;
+      return bReturn;
     }
 
-    inline ~CCondition(void)
+    inline void Unlock(void)
     {
-      Broadcast();
-      ConditionDelete(m_condition);
+      if (m_bIsLocked)
+      {
+        m_bIsLocked = false;
+        m_mutex.Unlock();
+      }
     }
 
-    inline void Broadcast(void)
+    inline bool Clear(void)
     {
-      ConditionBroadcast(m_condition);
+      m_bIsLocked = false;
+      return m_mutex.Clear();
     }
 
-    inline void Signal(void)
+    inline bool Lock(void)
     {
-      ConditionSignal(m_condition);
+      bool bReturn = m_mutex.Lock();
+      m_bIsLocked |= bReturn;
+      return bReturn;
     }
 
-    inline bool Wait(CMutex &mutex, uint32_t iTimeout = 0)
+    inline bool IsLocked(void) const
     {
-      return ConditionWait(m_condition, mutex.m_mutex, iTimeout);
+      return m_bIsLocked;
+    }
+
+  private:
+    CMutex &      m_mutex;
+    bool          m_bClearOnExit;
+    volatile bool m_bIsLocked;
+  };
+
+  template <typename _Predicate>
+    class CCondition : public PreventCopy
+    {
+    public:
+      inline CCondition(void) {}
+      inline ~CCondition(void)
+      {
+        m_condition.Broadcast();
+      }
+
+      inline void Broadcast(void)
+      {
+        m_condition.Broadcast();
+      }
+
+      inline void Signal(void)
+      {
+        m_condition.Signal();
+      }
+
+      inline bool Wait(CMutex &mutex, _Predicate &predicate)
+      {
+        while(!predicate)
+          m_condition.Wait(mutex.m_mutex);
+        return true;
+      }
+
+      inline bool Wait(CMutex &mutex, _Predicate &predicate, uint32_t iTimeout)
+      {
+        if (iTimeout == 0)
+          return Wait(mutex, predicate);
+
+        if (predicate)
+          return true;
+
+        bool bReturn(false);
+        bool bBreak(false);
+        CTimeout timeout(iTimeout);
+        uint32_t iMsLeft(0);
+
+        while (!bReturn && !bBreak)
+        {
+          iMsLeft = timeout.TimeLeft();
+          if ((bReturn = predicate) == false && (bBreak = iMsLeft == 0) == false)
+            m_condition.Wait(mutex.m_mutex, iMsLeft);
+        }
+        return bReturn;
+      }
+
+    private:
+      CConditionImpl m_condition;
+    };
+
+  class CEvent
+  {
+  public:
+    CEvent(bool bAutoReset = true) :
+      m_bSignaled(false),
+      m_bBroadcast(false),
+      m_iWaitingThreads(0),
+      m_bAutoReset(bAutoReset) {}
+    virtual ~CEvent(void) {}
+
+    void Broadcast(void)
+    {
+      Set(true);
+      m_condition.Broadcast();
+    }
+
+    void Signal(void)
+    {
+      Set(false);
+      m_condition.Signal();
+    }
+
+    bool Wait(void)
+    {
+      CLockObject lock(m_mutex);
+      ++m_iWaitingThreads;
+
+      bool bReturn = m_condition.Wait(m_mutex, m_bSignaled);
+      return ResetAndReturn() && bReturn;
+    }
+
+    bool Wait(uint32_t iTimeout)
+    {
+      if (iTimeout == 0)
+        return Wait();
+
+      CLockObject lock(m_mutex);
+      ++m_iWaitingThreads;
+      bool bReturn = m_condition.Wait(m_mutex, m_bSignaled, iTimeout);
+      return ResetAndReturn() && bReturn;
     }
 
     static void Sleep(uint32_t iTimeout)
     {
-      CCondition w;
-      CMutex m;
-      CLockObject lock(m);
-      w.Wait(m, iTimeout);
+      CEvent event;
+      event.Wait(iTimeout);
+    }
+
+  private:
+    void Set(bool bBroadcast = false)
+    {
+      CLockObject lock(m_mutex);
+      m_bSignaled  = true;
+      m_bBroadcast = bBroadcast;
+    }
+
+    bool ResetAndReturn(void)
+    {
+      CLockObject lock(m_mutex);
+      bool bReturn(m_bSignaled);
+      if (bReturn && (--m_iWaitingThreads == 0 || !m_bBroadcast) && m_bAutoReset)
+        m_bSignaled = false;
+      return bReturn;
     }
 
-    condition_t m_condition;
+    volatile bool             m_bSignaled;
+    CCondition<volatile bool> m_condition;
+    CMutex                    m_mutex;
+    volatile bool             m_bBroadcast;
+    unsigned int              m_iWaitingThreads;
+    bool                      m_bAutoReset;
   };
 }