2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/devel-api/threading/conditional-wait.h>
23 #include <condition_variable>
26 #include <dali/integration-api/debug.h>
27 #include <dali/internal/common/mutex-trace.h>
32 * Data members for ConditionalWait
34 struct ConditionalWait::ConditionalWaitImpl
37 std::condition_variable condition;
38 volatile unsigned int count;
42 * Data members for ConditionalWait::ScopedLock
44 struct ConditionalWait::ScopedLock::ScopedLockImpl
46 ScopedLockImpl( ConditionalWait& wait )
48 lock( wait.mImpl->mutex ) // locks for the lifecycle of this object
50 ConditionalWait& wait;
51 std::unique_lock<std::mutex> lock;
54 ConditionalWait::ScopedLock::ScopedLock( ConditionalWait& wait )
55 : mImpl( new ConditionalWait::ScopedLock::ScopedLockImpl( wait ) )
57 Internal::MutexTrace::Lock(); // matching sequence in mutex.cpp
60 ConditionalWait::ScopedLock::~ScopedLock()
62 Internal::MutexTrace::Unlock();
66 ConditionalWait& ConditionalWait::ScopedLock::GetLockedWait() const
68 return mImpl->wait; // mImpl can never be NULL
71 ConditionalWait::ConditionalWait()
72 : mImpl( new ConditionalWaitImpl )
77 ConditionalWait::~ConditionalWait()
82 void ConditionalWait::Notify()
84 // conditional wait requires a lock to be held
85 ScopedLock lock( *this );
86 volatile unsigned int previousCount = mImpl->count;
87 mImpl->count = 0; // change state before broadcast as that may wake clients immediately
88 // notify does nothing if the thread is not waiting but still has a system call overhead
89 // notify all threads to continue
90 if( 0 != previousCount )
92 mImpl->condition.notify_all(); // no return value
96 void ConditionalWait::Notify( const ScopedLock& scope )
98 // Scope must be locked:
99 DALI_ASSERT_DEBUG( &scope.GetLockedWait() == this );
101 volatile unsigned int previousCount = mImpl->count;
102 mImpl->count = 0; // change state before broadcast as that may wake clients immediately
103 // notify does nothing if the thread is not waiting but still has a system call overhead
104 // notify all threads to continue
105 if( 0 != previousCount )
107 mImpl->condition.notify_all(); // no return value
111 void ConditionalWait::Wait()
113 // conditional wait requires a lock to be held
114 ScopedLock scope( *this );
116 // conditional wait may wake up without anyone calling Notify
119 // wait while condition changes
120 mImpl->condition.wait( scope.mImpl->lock ); // need to pass in the std::unique_lock
122 while( 0 != mImpl->count );
125 void ConditionalWait::Wait( const ScopedLock& scope )
127 // Scope must be locked:
128 DALI_ASSERT_DEBUG( &scope.GetLockedWait() == this );
132 // conditional wait may wake up without anyone calling Notify
135 // wait while condition changes
136 mImpl->condition.wait( scope.mImpl->lock ); // need to pass in the std::unique_lock
138 while( 0 != mImpl->count );
140 // We return with our mutex locked safe in the knowledge that the ScopedLock
141 // passed in will unlock it in the caller.
144 unsigned int ConditionalWait::GetWaitCount() const