2 * Copyright (c) 2020 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>
22 #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
51 ConditionalWait& wait;
52 std::unique_lock<std::mutex> lock;
55 ConditionalWait::ScopedLock::ScopedLock(ConditionalWait& wait)
56 : mImpl(new ConditionalWait::ScopedLock::ScopedLockImpl(wait))
58 Internal::MutexTrace::Lock(); // matching sequence in mutex.cpp
61 ConditionalWait::ScopedLock::~ScopedLock()
63 Internal::MutexTrace::Unlock();
67 ConditionalWait& ConditionalWait::ScopedLock::GetLockedWait() const
69 return mImpl->wait; // mImpl can never be NULL
72 ConditionalWait::ConditionalWait()
73 : mImpl(new ConditionalWaitImpl)
78 ConditionalWait::~ConditionalWait()
83 void ConditionalWait::Notify()
85 // conditional wait requires a lock to be held
86 ScopedLock lock(*this);
87 volatile unsigned int previousCount = mImpl->count;
89 mImpl->count = 0; // change state before broadcast as that may wake clients immediately
90 // notify does nothing if the thread is not waiting but still has a system call overhead
91 // notify all threads to continue
92 if(0 != previousCount)
94 mImpl->condition.notify_all(); // no return value
98 void ConditionalWait::Notify(const ScopedLock& scope)
100 // Scope must be locked:
101 DALI_ASSERT_DEBUG(&scope.GetLockedWait() == this);
103 volatile unsigned int previousCount = mImpl->count;
105 mImpl->count = 0; // change state before broadcast as that may wake clients immediately
106 // notify does nothing if the thread is not waiting but still has a system call overhead
107 // notify all threads to continue
108 if(0 != previousCount)
110 mImpl->condition.notify_all(); // no return value
114 void ConditionalWait::Wait()
116 // conditional wait requires a lock to be held
117 ScopedLock scope(*this);
119 // conditional wait may wake up without anyone calling Notify
122 // wait while condition changes
123 mImpl->condition.wait(scope.mImpl->lock); // need to pass in the std::unique_lock
124 } while(0 != mImpl->count);
127 void ConditionalWait::Wait(const ScopedLock& scope)
129 // Scope must be locked:
130 DALI_ASSERT_DEBUG(&scope.GetLockedWait() == this);
134 // conditional wait may wake up without anyone calling Notify
137 // wait while condition changes
138 mImpl->condition.wait(scope.mImpl->lock); // need to pass in the std::unique_lock
139 } while(0 != mImpl->count);
141 // We return with our mutex locked safe in the knowledge that the ScopedLock
142 // passed in will unlock it in the caller.
145 unsigned int ConditionalWait::GetWaitCount() const