Replace boost::mutex with a Dali::Mutex to remove dependency to boost thread library 17/35617/9
authorKimmo Hoikka <kimmo.hoikka@samsung.com>
Thu, 19 Feb 2015 11:57:48 +0000 (11:57 +0000)
committerKimmo Hoikka <kimmo.hoikka@samsung.com>
Fri, 20 Feb 2015 19:13:56 +0000 (19:13 +0000)
Change-Id: I040e1f76638662476c7280d351417ffc6e0d5043

automated-tests/src/dali/CMakeLists.txt
automated-tests/src/dali/utc-Dali-Mutex.cpp [new file with mode: 0644]
build/tizen/dali-core/Makefile.am
dali/internal/event/common/notification-manager.cpp
dali/internal/update/queue/update-message-queue.cpp
dali/public-api/common/mutex.cpp [new file with mode: 0644]
dali/public-api/common/mutex.h [new file with mode: 0644]
dali/public-api/dali-core.h
dali/public-api/file.list

index 5266f3f..072ad59 100644 (file)
@@ -56,6 +56,7 @@ SET(TC_SOURCES
         utc-Dali-MeshData.cpp
         utc-Dali-Model.cpp
         utc-Dali-MouseWheelEvent.cpp
+        utc-Dali-Mutex.cpp
         utc-Dali-NinePatchImages.cpp
         utc-Dali-ObjectRegistry.cpp
         utc-Dali-PanGesture.cpp
@@ -127,6 +128,7 @@ INCLUDE_DIRECTORIES(
 ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
 TARGET_LINK_LIBRARIES(${EXEC_NAME}
     ${${CAPI_LIB}_LIBRARIES}
+    -lpthread
 )
 
 INSTALL(PROGRAMS ${EXEC_NAME}
diff --git a/automated-tests/src/dali/utc-Dali-Mutex.cpp b/automated-tests/src/dali/utc-Dali-Mutex.cpp
new file mode 100644 (file)
index 0000000..d9f902d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dali/public-api/dali-core.h>
+#include <dali-test-suite-utils.h>
+
+using Dali::Mutex;
+
+int UtcDaliMutexSingleThread(void)
+{
+  tet_infoline("Testing Dali::Mutex in a single thread");
+
+  {
+    Mutex mutex1;
+    DALI_TEST_EQUALS( false, mutex1.IsLocked(), TEST_LOCATION );
+  }
+
+  {
+    Mutex mutex2;
+    Mutex::ScopedLock lock( mutex2 );
+    DALI_TEST_EQUALS( true, mutex2.IsLocked(), TEST_LOCATION );
+  }
+
+  Mutex mutex3;
+  {
+    Mutex::ScopedLock lock( mutex3 );
+  }
+  DALI_TEST_EQUALS( false, mutex3.IsLocked(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+namespace // for local variables to avoid name clashes
+{
+int gGlobalValue = 0;
+Mutex* gGlobalValueMutex;
+bool gWorkerThreadWait = true;
+enum ThreadState { INIT, RUN, LOCKING, TERMINATE } gWorkerThreadState = INIT;
+}
+void* WorkerThread1( void* ptr )
+{
+  gWorkerThreadState = RUN;
+  {
+    Mutex::ScopedLock lock( *gGlobalValueMutex );
+    gWorkerThreadState = LOCKING;
+    gGlobalValue = -1;
+    while( gWorkerThreadWait ) // wait till we can exit
+    {
+      usleep( 1 ); // 1 microsecond
+    }
+  }
+  gWorkerThreadState = TERMINATE;
+  return NULL;
+}
+
+int UtcDaliMutexMultiThread(void)
+{
+  tet_infoline("Testing Dali::Mutex multithreaded");
+
+  gGlobalValueMutex = new Dali::Mutex;
+
+  pthread_t thread1;
+  // initialize values
+  gGlobalValue = 0;
+  gWorkerThreadWait = true;
+  DALI_TEST_EQUALS( INIT, gWorkerThreadState, TEST_LOCATION );
+  DALI_TEST_EQUALS( 0, gGlobalValue, TEST_LOCATION );
+  DALI_TEST_EQUALS( false, gGlobalValueMutex->IsLocked(), TEST_LOCATION );
+
+  // lock the mutex
+  {
+    Mutex::ScopedLock lock( *gGlobalValueMutex );
+    DALI_TEST_EQUALS( true, gGlobalValueMutex->IsLocked(), TEST_LOCATION );
+    pthread_create(&thread1, NULL, &WorkerThread1, NULL );
+    // wait till the thread is in run state
+    while( RUN != gWorkerThreadState )
+    {
+      usleep( 1 ); // 1 microsecond
+    }
+    // now the thread is running and mutex is still locked by this thread so value is not changed
+    DALI_TEST_EQUALS( true, gGlobalValueMutex->IsLocked(), TEST_LOCATION );
+    DALI_TEST_EQUALS( 0, gGlobalValue, TEST_LOCATION );
+    // drop out of scope, releases our lock
+  }
+  // now child thread is allowed to change the value
+  // wait till the thread is in locking state
+  while( LOCKING != gWorkerThreadState )
+  {
+    usleep( 1 ); // 1 microsecond
+  }
+  // mutex is locked, but not by us, by the child thread
+  DALI_TEST_EQUALS( true, gGlobalValueMutex->IsLocked(), TEST_LOCATION );
+  // value is changed
+  DALI_TEST_EQUALS( -1, gGlobalValue, TEST_LOCATION );
+  // let worker finish
+  gWorkerThreadWait = false;
+  // wait till the thread is terminated state
+  while( TERMINATE != gWorkerThreadState )
+  {
+    usleep( 1 ); // 1 microsecond
+  }
+  DALI_TEST_EQUALS( false, gGlobalValueMutex->IsLocked(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMutexNonCopyable(void)
+{
+  // we want to make sure that mutex is not copyable (its copy constructor is not defined)
+  // this test will stop compiling if Mutex has compiler generated copy constructor
+  DALI_COMPILE_TIME_ASSERT( !__has_trivial_copy( Mutex ) );
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+
index 2550e5e..2d55f6e 100644 (file)
@@ -72,8 +72,7 @@ libdali_core_la_CXXFLAGS = -DDALI_COMPILATION \
                            $(DALI_CFLAGS)
 
 libdali_core_la_LIBADD = $(DALI_LDFLAGS) \
-                         -lboost_thread \
-                         -lboost_system
+                         -lpthread
 
 # Create an empty shaderbin dir
 install-data-local:
index 0c0d30c..0212cd9 100644 (file)
 // CLASS HEADER
 #include <dali/internal/event/common/notification-manager.h>
 
-// EXTERNAL INCLUDES
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wall"
-
-#include <boost/thread/mutex.hpp>
-
-#pragma clang diagnostic pop
-#else
-
-#include <boost/thread/mutex.hpp>
-
-#endif // __clang__
-
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/mutex.h>
 #include <dali/internal/common/owner-container.h>
 #include <dali/internal/common/message.h>
 #include <dali/internal/event/common/property-notification-impl.h>
@@ -80,7 +67,7 @@ void MoveElements( InterfaceContainer& from, InterfaceContainer& to )
 }
 }
 
-typedef boost::mutex MessageQueueMutex;
+typedef Dali::Mutex MessageQueueMutex;
 typedef OwnerContainer< MessageBase* > MessageContainer;
 
 struct NotificationManager::Impl
@@ -128,7 +115,7 @@ NotificationManager::~NotificationManager()
 void NotificationManager::QueueCompleteNotification( CompleteNotificationInterface* instance )
 {
   // queueMutex must be locked whilst accessing queues
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
 
   mImpl->updateWorkingInterfaceQueue.PushBack( instance );
 }
@@ -138,7 +125,7 @@ void NotificationManager::QueueMessage( MessageBase* message )
   DALI_ASSERT_DEBUG( NULL != message );
 
   // queueMutex must be locked whilst accessing queues
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
 
   mImpl->updateWorkingMessageQueue.PushBack( message );
 }
@@ -146,7 +133,7 @@ void NotificationManager::QueueMessage( MessageBase* message )
 void NotificationManager::UpdateCompleted()
 {
   // queueMutex must be locked whilst accessing queues
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
   // Move messages from update working queue to completed queue
   // note that in theory its possible for update completed to have last frames
   // events as well still hanging around. we need to keep them as well
@@ -159,7 +146,7 @@ void NotificationManager::UpdateCompleted()
 bool NotificationManager::MessagesToProcess()
 {
   // queueMutex must be locked whilst accessing queues
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
 
   return ( 0u < mImpl->updateCompletedMessageQueue.Count() ||
          ( 0u < mImpl->updateCompletedInterfaceQueue.Count() ) );
@@ -169,7 +156,7 @@ void NotificationManager::ProcessMessages()
 {
   // queueMutex must be locked whilst accessing queues
   {
-    MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+    MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
 
     // Move messages from update completed queue to event queue
     // note that in theory its possible for event queue to have
index c435584..a89a760 100644 (file)
 // CLASS HEADER
 #include <dali/internal/update/queue/update-message-queue.h>
 
-// EXTERNAL INCLUDES
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wall"
-#include <boost/thread/mutex.hpp>
-#pragma clang diagnostic pop
-#else
-#include <boost/thread/mutex.hpp>
-#endif // ifdef __clang
-
 // INTERNAL INCLUDES
 #include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/common/mutex.h>
 #include <dali/integration-api/render-controller.h>
 #include <dali/internal/common/message-buffer.h>
 #include <dali/internal/render/common/performance-monitor.h>
@@ -58,7 +49,7 @@ static const std::size_t MAX_FREE_BUFFER_COUNT = 3; // Allow this number of buff
 typedef vector< MessageBuffer* > MessageBufferQueue;
 typedef MessageBufferQueue::iterator MessageBufferIter;
 
-typedef boost::mutex MessageQueueMutex;
+typedef Dali::Mutex MessageQueueMutex;
 
 } // unnamed namespace
 
@@ -215,7 +206,7 @@ bool MessageQueue::FlushQueue()
   if ( messagesToProcess )
   {
     // queueMutex must be locked whilst accessing processQueue or recycleQueue
-    MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+    MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
 
     mImpl->processQueue.push_back( mImpl->currentMessageBuffer );
     mImpl->currentMessageBuffer = NULL;
@@ -255,7 +246,7 @@ void MessageQueue::ProcessMessages()
   PERF_MONITOR_START(PerformanceMonitor::PROCESS_MESSAGES);
 
   // queueMutex must be locked whilst accessing queue
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
 
   const MessageBufferIter processQueueEndIter = mImpl->processQueue.end();
   for ( MessageBufferIter iter = mImpl->processQueue.begin(); iter != processQueueEndIter ; ++iter )
diff --git a/dali/public-api/common/mutex.cpp b/dali/public-api/common/mutex.cpp
new file mode 100644 (file)
index 0000000..49630e7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/common/mutex.h>
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+
+namespace Dali
+{
+
+struct Mutex::MutexImpl
+{
+  pthread_mutex_t mutex;
+  bool locked;
+};
+
+Mutex::Mutex()
+: mImpl( new MutexImpl )
+{
+  pthread_mutex_init( &mImpl->mutex, NULL );
+  mImpl->locked = false;
+}
+
+Mutex::~Mutex()
+{
+  pthread_mutex_destroy( &mImpl->mutex );
+  // nothing else to do as there is no Lock/Unlock API
+  // ScopedLock destructor will always unlock the mutex
+  delete mImpl;
+}
+
+bool Mutex::IsLocked()
+{
+  return mImpl->locked;
+}
+
+Mutex::ScopedLock::ScopedLock( Mutex& mutex )
+: mMutex( mutex )
+{
+  pthread_mutex_lock( &mMutex.mImpl->mutex );
+  mMutex.mImpl->locked = true;
+}
+
+Mutex::ScopedLock::~ScopedLock()
+{
+  pthread_mutex_unlock( &mMutex.mImpl->mutex );
+  mMutex.mImpl->locked = false;
+}
+
+} // namespace Dali
diff --git a/dali/public-api/common/mutex.h b/dali/public-api/common/mutex.h
new file mode 100644 (file)
index 0000000..cd41f9a
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __DALI_MUTEX_H__
+#define __DALI_MUTEX_H__
+
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+/**
+ * The top level DALi namespace
+ */
+namespace Dali
+{
+
+/**
+ * Class to synchronize access to critical resources from multiple threads
+ */
+class DALI_IMPORT_API Mutex
+{
+public:
+
+  /**
+   * @brief Constructor, acquires the mutex from the underlying OS
+   */
+  Mutex();
+
+  /**
+   * @brief Destructor, non virtual as this is not meant as a base class
+   */
+  ~Mutex();
+
+  /**
+   * @brief Check if the mutex is locked
+   * @return true if the mutex is locked
+   */
+  bool IsLocked();
+
+public:
+
+  /**
+   * Helper class to do a scoped lock on a mutex implementing the RAII idiom.
+   * Note! this class *does not* prevent a deadlock in the case when same thread is
+   * locking the same mutex twice.
+   */
+  class ScopedLock
+  {
+  public:
+
+    /**
+     * Constructor
+     * @param mutex to lock
+     */
+    ScopedLock( Mutex& mutex );
+
+    /**
+     * Destructor, releases the lock
+     */
+    ~ScopedLock();
+
+  private:
+    Mutex& mMutex;
+  };
+
+private:
+
+  /// Not implemented as Mutex is not copyable
+  Mutex( const Mutex& );
+  const Mutex& operator= ( const Mutex& );
+
+  struct MutexImpl;
+  MutexImpl* mImpl;
+
+};
+
+} // namespace Dali
+
+#endif // __DALI_MUTEX_H__
index a93286b..35aa175 100644 (file)
@@ -54,6 +54,7 @@
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/common/light.h>
 #include <dali/public-api/common/loading-state.h>
+#include <dali/public-api/common/mutex.h>
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/common/view-mode.h>
index 633735d..83d25a3 100644 (file)
@@ -26,6 +26,7 @@ public_api_src_files = \
   $(public_api_src_dir)/common/dali-common.cpp \
   $(public_api_src_dir)/common/dali-vector.cpp \
   $(public_api_src_dir)/common/light.cpp \
+  $(public_api_src_dir)/common/mutex.cpp \
   $(public_api_src_dir)/common/stage.cpp \
   $(public_api_src_dir)/dynamics/dynamics-body.cpp \
   $(public_api_src_dir)/dynamics/dynamics-body-config.cpp \
@@ -165,6 +166,7 @@ public_api_core_common_header_files = \
   $(public_api_src_dir)/common/intrusive-ptr.h \
   $(public_api_src_dir)/common/light.h \
   $(public_api_src_dir)/common/loading-state.h \
+  $(public_api_src_dir)/common/mutex.h \
   $(public_api_src_dir)/common/map-wrapper.h \
   $(public_api_src_dir)/common/ref-counted-dali-vector.h \
   $(public_api_src_dir)/common/set-wrapper.h \