[4.0] Change Dali::Thread, Dali::Mutex and Dali::ConditionalWait to use std::thread...
[platform/core/uifw/dali-core.git] / dali / devel-api / threading / conditional-wait.cpp
index adc5760..fa0a86c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/devel-api/threading/conditional-wait.h>
 
 // EXTERNAL INCLUDES
-#include <pthread.h>
+#include <mutex>
+#include <condition_variable>
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
-#include <dali/internal/common/mutex-impl.h>
+#include <dali/internal/common/mutex-trace.h>
 
 namespace Dali
 {
-
+/**
+ * Data members for ConditionalWait
+ */
 struct ConditionalWait::ConditionalWaitImpl
 {
-  pthread_mutex_t mutex;
-  pthread_cond_t condition;
+  std::mutex mutex;
+  std::condition_variable condition;
   volatile unsigned int count;
 };
 
+/**
+ * Data members for ConditionalWait::ScopedLock
+ */
+struct ConditionalWait::ScopedLock::ScopedLockImpl
+{
+  ScopedLockImpl( ConditionalWait& wait )
+  : wait( wait ),
+    lock( wait.mImpl->mutex ) // locks for the lifecycle of this object
+  { }
+  ConditionalWait& wait;
+  std::unique_lock<std::mutex> lock;
+};
 
-ConditionalWait::ScopedLock::ScopedLock( ConditionalWait& wait ) : mWait(wait)
+ConditionalWait::ScopedLock::ScopedLock( ConditionalWait& wait )
+: mImpl( new ConditionalWait::ScopedLock::ScopedLockImpl( wait ) )
 {
-  Internal::Mutex::Lock( &wait.mImpl->mutex );
+  Internal::MutexTrace::Lock(); // matching sequence in mutex.cpp
 }
 
 ConditionalWait::ScopedLock::~ScopedLock()
 {
-  ConditionalWait& wait = mWait;
-  Internal::Mutex::Unlock( &wait.mImpl->mutex );
+  Internal::MutexTrace::Unlock();
+  delete mImpl;
+}
+
+ConditionalWait& ConditionalWait::ScopedLock::GetLockedWait() const
+{
+  return mImpl->wait; // mImpl can never be NULL
 }
 
 ConditionalWait::ConditionalWait()
 : mImpl( new ConditionalWaitImpl )
 {
-  if( pthread_mutex_init( &mImpl->mutex, NULL ) )
-  {
-    DALI_LOG_ERROR( "Unable to initialise mutex in ConditionalWait\n" );
-  }
-  if( pthread_cond_init( &mImpl->condition, NULL ) )
-  {
-    DALI_LOG_ERROR( "Unable to initialise conditional\n" );
-  }
   mImpl->count = 0;
 }
 
 ConditionalWait::~ConditionalWait()
 {
-  if( pthread_cond_destroy( &mImpl->condition ) )
-  {
-    DALI_LOG_ERROR( "Unable to destroy conditional\n" );
-  }
-  if( pthread_mutex_destroy( &mImpl->mutex ) )
-  {
-    DALI_LOG_ERROR( "Unable to destroy mutex in ConditionalWait\n" );
-  }
   delete mImpl;
 }
 
 void ConditionalWait::Notify()
 {
-  // pthread_cond_wait requires a lock to be held
-  Internal::Mutex::Lock( &mImpl->mutex );
+  // conditional wait requires a lock to be held
+  ScopedLock lock( *this );
   volatile unsigned int previousCount = mImpl->count;
   mImpl->count = 0; // change state before broadcast as that may wake clients immediately
-  // broadcast does nothing if the thread is not waiting but still has a system call overhead
-  // broadcast all threads to continue
+  // notify does nothing if the thread is not waiting but still has a system call overhead
+  // notify all threads to continue
   if( 0 != previousCount )
   {
-    if( pthread_cond_broadcast( &mImpl->condition ) )
-    {
-      DALI_LOG_ERROR( "Error calling pthread_cond_broadcast\n" );
-    }
+    mImpl->condition.notify_all(); // no return value
   }
-  Internal::Mutex::Unlock( &mImpl->mutex );
 }
 
 void ConditionalWait::Notify( const ScopedLock& scope )
@@ -99,35 +100,26 @@ void ConditionalWait::Notify( const ScopedLock& scope )
 
   volatile unsigned int previousCount = mImpl->count;
   mImpl->count = 0; // change state before broadcast as that may wake clients immediately
-  // broadcast does nothing if the thread is not waiting but still has a system call overhead
-  // broadcast all threads to continue
+  // notify does nothing if the thread is not waiting but still has a system call overhead
+  // notify all threads to continue
   if( 0 != previousCount )
   {
-    if( pthread_cond_broadcast( &mImpl->condition ) )
-    {
-      DALI_LOG_ERROR( "Error calling pthread_cond_broadcast\n" );
-    }
+    mImpl->condition.notify_all(); // no return value
   }
 }
 
 void ConditionalWait::Wait()
 {
-  // pthread_cond_wait requires a lock to be held
-  Internal::Mutex::Lock( &mImpl->mutex );
+  // conditional wait requires a lock to be held
+  ScopedLock scope( *this );
   ++(mImpl->count);
-  // pthread_cond_wait may wake up without anyone calling Notify
+  // conditional wait may wake up without anyone calling Notify
   do
   {
     // wait while condition changes
-    if( pthread_cond_wait( &mImpl->condition, &mImpl->mutex ) ) // releases the lock whilst waiting
-    {
-      DALI_LOG_ERROR( "Error calling pthread_cond_wait\n" );
-      break;
-    }
+    mImpl->condition.wait( scope.mImpl->lock ); // need to pass in the std::unique_lock
   }
   while( 0 != mImpl->count );
-  // when condition returns the mutex is locked so release the lock
-  Internal::Mutex::Unlock( &mImpl->mutex );
 }
 
 void ConditionalWait::Wait( const ScopedLock& scope )
@@ -137,16 +129,11 @@ void ConditionalWait::Wait( const ScopedLock& scope )
 
   ++(mImpl->count);
 
-  // pthread_cond_wait may wake up without anyone calling Notify so loop until
-  // count has been reset in a notify:
+  // conditional wait may wake up without anyone calling Notify
   do
   {
     // wait while condition changes
-    if( pthread_cond_wait( &mImpl->condition, &mImpl->mutex ) ) // releases the lock whilst waiting
-    {
-      DALI_LOG_ERROR( "Error calling pthread_cond_wait\n" );
-      break;
-    }
+    mImpl->condition.wait( scope.mImpl->lock ); // need to pass in the std::unique_lock
   }
   while( 0 != mImpl->count );