From 48c55fa64f7de0c346dbd41a96391344aaebb6bf Mon Sep 17 00:00:00 2001 From: Kimmo Hoikka Date: Thu, 19 Feb 2015 11:57:48 +0000 Subject: [PATCH] Replace boost::mutex with a Dali::Mutex to remove dependency to boost thread library Change-Id: I040e1f76638662476c7280d351417ffc6e0d5043 --- automated-tests/src/dali/CMakeLists.txt | 2 + automated-tests/src/dali/utc-Dali-Mutex.cpp | 134 +++++++++++++++++++++ build/tizen/dali-core/Makefile.am | 3 +- .../internal/event/common/notification-manager.cpp | 27 ++--- .../internal/update/queue/update-message-queue.cpp | 17 +-- dali/public-api/common/mutex.cpp | 66 ++++++++++ dali/public-api/common/mutex.h | 92 ++++++++++++++ dali/public-api/dali-core.h | 1 + dali/public-api/file.list | 2 + 9 files changed, 309 insertions(+), 35 deletions(-) create mode 100644 automated-tests/src/dali/utc-Dali-Mutex.cpp create mode 100644 dali/public-api/common/mutex.cpp create mode 100644 dali/public-api/common/mutex.h diff --git a/automated-tests/src/dali/CMakeLists.txt b/automated-tests/src/dali/CMakeLists.txt index 5266f3f..072ad59 100644 --- a/automated-tests/src/dali/CMakeLists.txt +++ b/automated-tests/src/dali/CMakeLists.txt @@ -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 index 0000000..d9f902d --- /dev/null +++ b/automated-tests/src/dali/utc-Dali-Mutex.cpp @@ -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 +#include +#include +#include +#include + +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; +} + + diff --git a/build/tizen/dali-core/Makefile.am b/build/tizen/dali-core/Makefile.am index 2550e5e..2d55f6e 100644 --- a/build/tizen/dali-core/Makefile.am +++ b/build/tizen/dali-core/Makefile.am @@ -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: diff --git a/dali/internal/event/common/notification-manager.cpp b/dali/internal/event/common/notification-manager.cpp index 0c0d30c..0212cd9 100644 --- a/dali/internal/event/common/notification-manager.cpp +++ b/dali/internal/event/common/notification-manager.cpp @@ -18,22 +18,9 @@ // CLASS HEADER #include -// EXTERNAL INCLUDES -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wall" - -#include - -#pragma clang diagnostic pop -#else - -#include - -#endif // __clang__ - // INTERNAL INCLUDES #include +#include #include #include #include @@ -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 diff --git a/dali/internal/update/queue/update-message-queue.cpp b/dali/internal/update/queue/update-message-queue.cpp index c435584..a89a760 100644 --- a/dali/internal/update/queue/update-message-queue.cpp +++ b/dali/internal/update/queue/update-message-queue.cpp @@ -18,18 +18,9 @@ // CLASS HEADER #include -// EXTERNAL INCLUDES -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wall" -#include -#pragma clang diagnostic pop -#else -#include -#endif // ifdef __clang - // INTERNAL INCLUDES #include +#include #include #include #include @@ -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 index 0000000..49630e7 --- /dev/null +++ b/dali/public-api/common/mutex.cpp @@ -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 + +// EXTERNAL INCLUDES +#include + +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 index 0000000..cd41f9a --- /dev/null +++ b/dali/public-api/common/mutex.h @@ -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 + +/** + * 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__ diff --git a/dali/public-api/dali-core.h b/dali/public-api/dali-core.h index a93286b..35aa175 100644 --- a/dali/public-api/dali-core.h +++ b/dali/public-api/dali-core.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/dali/public-api/file.list b/dali/public-api/file.list index 633735d..83d25a3 100644 --- a/dali/public-api/file.list +++ b/dali/public-api/file.list @@ -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 \ -- 2.7.4