/*
- * 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 )
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 )
++(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 );