cec: use a recursive mutex
[deb_libcec.git] / src / lib / platform / threads.cpp
index 08a4c3b8884c39e9ce775212e8d5665a78175316..9ea0008e713f81065aed63d85194e24eafad79a0 100644 (file)
@@ -37,7 +37,7 @@ using namespace CEC;
 
 CMutex::CMutex(void)
 {
-  pthread_mutex_init(&m_mutex, NULL);
+  pthread_mutex_init(&m_mutex, GetMutexAttribute());
 }
 
 CMutex::~CMutex(void)
@@ -60,11 +60,24 @@ void CMutex::Unlock(void)
   pthread_mutex_unlock(&m_mutex);
 }
 
-CLockObject::CLockObject(CMutex *mutex) :
+static pthread_mutexattr_t g_mutexAttr;
+pthread_mutexattr_t *CMutex::GetMutexAttribute()
+{
+  static bool bAttributeInitialised = false;
+  if (!bAttributeInitialised)
+  {
+    pthread_mutexattr_init(&g_mutexAttr);
+    pthread_mutexattr_settype(&g_mutexAttr, PTHREAD_MUTEX_RECURSIVE);
+    bAttributeInitialised = true;
+  }
+  return &g_mutexAttr;
+}
+
+CLockObject::CLockObject(CMutex *mutex, bool bTryLock /* = false */) :
   m_mutex(mutex)
 {
   if (m_mutex)
-    m_mutex->Lock();
+    m_bLocked = bTryLock ? m_mutex->TryLock() : m_mutex->Lock();
 }
 
 CLockObject::~CLockObject(void)
@@ -75,14 +88,17 @@ CLockObject::~CLockObject(void)
 
 void CLockObject::Leave(void)
 {
-  if (m_mutex)
+  if (m_mutex && m_bLocked)
+  {
+    m_bLocked = false;
     m_mutex->Unlock();
+  }
 }
 
 void CLockObject::Lock(void)
 {
   if (m_mutex)
-    m_mutex->Lock();
+    m_bLocked = m_mutex->Lock();
 }
 
 CCondition::CCondition(void)
@@ -106,27 +122,32 @@ void CCondition::Signal(void)
   pthread_cond_signal(&m_cond);
 }
 
-bool CCondition::Wait(CMutex *mutex, int64_t iTimeout)
+bool CCondition::Wait(CMutex *mutex, uint32_t iTimeout /* = 0 */)
 {
   bool bReturn(false);
   sched_yield();
   if (mutex)
   {
-    struct timespec abstime;
-    struct timeval now;
-    if (gettimeofday(&now, NULL) == 0)
+    if (iTimeout > 0)
     {
+      struct timespec abstime;
+      struct timeval now;
+      gettimeofday(&now, NULL);
       iTimeout       += now.tv_usec / 1000;
       abstime.tv_sec  = now.tv_sec + (time_t)(iTimeout / 1000);
-      abstime.tv_nsec = (long)((iTimeout % (unsigned long)1000) * (unsigned long)1000000);
+      abstime.tv_nsec = (int32_t)((iTimeout % (uint32_t)1000) * (uint32_t)1000000);
       bReturn         = (pthread_cond_timedwait(&m_cond, &mutex->m_mutex, &abstime) == 0);
     }
+    else
+    {
+      bReturn         = (pthread_cond_wait(&m_cond, &mutex->m_mutex) == 0);
+    }
   }
 
   return bReturn;
 }
 
-void CCondition::Sleep(int64_t iTimeout)
+void CCondition::Sleep(uint32_t iTimeout)
 {
   CCondition w;
   CMutex m;
@@ -135,19 +156,17 @@ void CCondition::Sleep(int64_t iTimeout)
 }
 
 CThread::CThread(void) :
-    m_bRunning(false),
-    m_bStop(false)
+    m_bStop(false),
+    m_bRunning(false)
 {
 }
 
 CThread::~CThread(void)
 {
-  m_bStop = true;
-  m_threadCondition.Broadcast();
-  pthread_join(m_thread, NULL);
+  StopThread();
 }
 
-bool CThread::CreateThread(void)
+bool CThread::CreateThread(bool bWait /* = true */)
 {
   bool bReturn(false);
 
@@ -155,7 +174,8 @@ bool CThread::CreateThread(void)
   m_bStop = false;
   if (!m_bRunning && pthread_create(&m_thread, NULL, (void *(*) (void *))&CThread::ThreadHandler, (void *)this) == 0)
   {
-    m_bRunning = true;
+    if (bWait)
+      m_threadCondition.Wait(&m_threadMutex);
     bReturn = true;
   }
 
@@ -167,27 +187,39 @@ void *CThread::ThreadHandler(CThread *thread)
   void *retVal = NULL;
 
   if (thread)
+  {
+    CLockObject lock(&thread->m_threadMutex);
+    thread->m_bRunning = true;
+    lock.Leave();
+    thread->m_threadCondition.Broadcast();
+
     retVal = thread->Process();
-  thread->m_bRunning = false;
+
+    lock.Lock();
+    thread->m_bRunning = false;
+    lock.Leave();
+    thread->m_threadCondition.Broadcast();
+  }
 
   return retVal;
 }
 
 bool CThread::StopThread(bool bWaitForExit /* = true */)
 {
-  bool bReturn(false);
+  bool bReturn(true);
   m_bStop = true;
 
   m_threadCondition.Broadcast();
+
   void *retVal;
-  if (bWaitForExit)
+  if (bWaitForExit && m_bRunning)
     bReturn = (pthread_join(m_thread, &retVal) == 0);
 
   return bReturn;
 }
 
-bool CThread::Sleep(uint64_t iTimeout)
+bool CThread::Sleep(uint32_t iTimeout)
 {
   CLockObject lock(&m_threadMutex);
-  return m_bStop ? false :m_threadCondition.Wait(&m_threadMutex, iTimeout);
+  return m_bStop ? false : m_threadCondition.Wait(&m_threadMutex, iTimeout);
 }