| Flutter Impeller |

thread.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef FLUTTER_IMPELLER_BASE_THREAD_H_
6 #define FLUTTER_IMPELLER_BASE_THREAD_H_
7
8 #include <chrono>
9 #include <condition_variable>
10 #include <functional>
11 #include <memory>
12 #include <mutex>
13 #include <shared_mutex>
14 #include <thread>
15
16 #include "impeller/base/thread_safety.h"
17
18 namespace impeller {
19
20 class ConditionVariable;
21
22 class IPLR_CAPABILITY("mutex") Mutex {
23 public:
24 Mutex() = default;
25
26 ~Mutex() = default;
27
28 void Lock() IPLR_ACQUIRE() { mutex_.lock(); }
29
30 void Unlock() IPLR_RELEASE() { mutex_.unlock(); }
31
32 private:
33 friend class ConditionVariable;
34
35 std::mutex mutex_;
36
37 Mutex(const Mutex&) = delete;
38
39 Mutex(Mutex&&) = delete;
40
41 Mutex& operator=(const Mutex&) = delete;
42
43 Mutex& operator=(Mutex&&) = delete;
44 };
45
46 class IPLR_CAPABILITY("mutex") RWMutex {
47 public:
48 RWMutex() = default;
49
50 ~RWMutex() = default;
51
52 void LockWriter() IPLR_ACQUIRE() { mutex_.lock(); }
53
54 void UnlockWriter() IPLR_RELEASE() { mutex_.unlock(); }
55
56 void LockReader() IPLR_ACQUIRE_SHARED() { mutex_.lock_shared(); }
57
58 void UnlockReader() IPLR_RELEASE_SHARED() { mutex_.unlock_shared(); }
59
60 private:
61 std::shared_mutex mutex_;
62
63 RWMutex(const RWMutex&) = delete;
64
65 RWMutex(RWMutex&&) = delete;
66
67 RWMutex& operator=(const RWMutex&) = delete;
68
69 RWMutex& operator=(RWMutex&&) = delete;
70 };
71
72 class IPLR_SCOPED_CAPABILITY Lock {
73 public:
74 explicit Lock(Mutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
75 mutex_.Lock();
76 }
77
78 ~Lock() IPLR_RELEASE() { mutex_.Unlock(); }
79
80 private:
81 Mutex& mutex_;
82
83 Lock(const Lock&) = delete;
84
85 Lock(Lock&&) = delete;
86
87 Lock& operator=(const Lock&) = delete;
88
89 Lock& operator=(Lock&&) = delete;
90 };
91
92 class IPLR_SCOPED_CAPABILITY ReaderLock {
93 public:
94 explicit ReaderLock(RWMutex& mutex) IPLR_ACQUIRE_SHARED(mutex)
95 : mutex_(mutex) {
96 mutex_.LockReader();
97 }
98
99 ~ReaderLock() IPLR_RELEASE() { mutex_.UnlockReader(); }
100
101 private:
102 RWMutex& mutex_;
103
104 ReaderLock(const ReaderLock&) = delete;
105
106 ReaderLock(ReaderLock&&) = delete;
107
108 ReaderLock& operator=(const ReaderLock&) = delete;
109
110 ReaderLock& operator=(ReaderLock&&) = delete;
111 };
112
113 class IPLR_SCOPED_CAPABILITY WriterLock {
114 public:
115 explicit WriterLock(RWMutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
116 mutex_.LockWriter();
117 }
118
119 ~WriterLock() IPLR_RELEASE() { mutex_.UnlockWriter(); }
120
121 private:
122 RWMutex& mutex_;
123
124 WriterLock(const WriterLock&) = delete;
125
126 WriterLock(WriterLock&&) = delete;
127
128 WriterLock& operator=(const WriterLock&) = delete;
129
130 WriterLock& operator=(WriterLock&&) = delete;
131 };
132
133 //------------------------------------------------------------------------------
134 /// @brief A condition variable exactly similar to the one in libcxx with
135 /// two major differences:
136 ///
137 /// * On the Wait, WaitFor, and WaitUntil calls, static analysis
138 /// annotation are respected.
139 /// * There is no ability to wait on a condition variable and also
140 /// be susceptible to spurious wakes. This is because the
141 /// predicate is mandatory.
142 ///
143 class ConditionVariable {
144 public:
145 ConditionVariable() = default;
146
147 ~ConditionVariable() = default;
148
149 ConditionVariable(const ConditionVariable&) = delete;
150
151 ConditionVariable& operator=(const ConditionVariable&) = delete;
152
153 void NotifyOne() { cv_.notify_one(); }
154
155 void NotifyAll() { cv_.notify_all(); }
156
157 using Predicate = std::function<bool()>;
158
159 //----------------------------------------------------------------------------
160 /// @brief Atomically unlocks the mutex and waits on the condition
161 /// variable up to a specified time point. Lock will be reacquired
162 /// when the wait exits. Spurious wakes may happen before the time
163 /// point is reached. In such cases the predicate is invoked and
164 /// it must return `false` for the wait to continue. The predicate
165 /// will be invoked with the mutex locked.
166 ///
167 /// @note Since the predicate is invoked with the mutex locked, if it
168 /// accesses other guarded resources, the predicate itself must be
169 /// decorated with the IPLR_REQUIRES directive. For instance,
170 ///
171 /// ```c++
172 /// [] () IPLR_REQUIRES(mutex) {
173 /// return my_guarded_resource.should_stop_waiting;
174 /// }
175 /// ```
176 ///
177 /// @param mutex The mutex.
178 /// @param[in] time_point The time point to wait to.
179 /// @param[in] should_stop_waiting The predicate invoked on spurious wakes.
180 /// Must return false for the wait to
181 /// continue.
182 ///
183 /// @tparam Clock The clock type.
184 /// @tparam Duration The duration type.
185 ///
186 /// @return The value of the predicate at the end of the wait.
187 ///
188 template <class Clock, class Duration>
189 bool WaitUntil(Mutex& mutex,
190 const std::chrono::time_point<Clock, Duration>& time_point,
191 const Predicate& should_stop_waiting) IPLR_REQUIRES(mutex) {
192 std::unique_lock lock(mutex.mutex_, std::adopt_lock);
193 const auto result = cv_.wait_until(lock, time_point, should_stop_waiting);
194 lock.release();
195 return result;
196 }
197
198 //----------------------------------------------------------------------------
199 /// @brief Atomically unlocks the mutex and waits on the condition
200 /// variable for a designated duration. Lock will be reacquired
201 /// when the wait exits. Spurious wakes may happen before the time
202 /// point is reached. In such cases the predicate is invoked and
203 /// it must return `false` for the wait to continue. The predicate
204 /// will be invoked with the mutex locked.
205 ///
206 /// @note Since the predicate is invoked with the mutex locked, if it
207 /// accesses other guarded resources, the predicate itself must be
208 /// decorated with the IPLR_REQUIRES directive. For instance,
209 ///
210 /// ```c++
211 /// [] () IPLR_REQUIRES(mutex) {
212 /// return my_guarded_resource.should_stop_waiting;
213 /// }
214 /// ```
215 ///
216 /// @param mutex The mutex.
217 /// @param[in] duration The duration to wait for.
218 /// @param[in] should_stop_waiting The predicate invoked on spurious wakes.
219 /// Must return false for the wait to
220 /// continue.
221 ///
222 /// @tparam Representation The duration representation type.
223 /// @tparam Period The duration period type.
224 ///
225 /// @return The value of the predicate at the end of the wait.
226 ///
227 template <class Representation, class Period>
228 bool WaitFor(Mutex& mutex,
229 const std::chrono::duration<Representation, Period>& duration,
230 const Predicate& should_stop_waiting) IPLR_REQUIRES(mutex) {
231 return WaitUntil(mutex, std::chrono::steady_clock::now() + duration,
232 should_stop_waiting);
233 }
234
235 //----------------------------------------------------------------------------
236 /// @brief Atomically unlocks the mutex and waits on the condition
237 /// variable indefinitely till the predicate determines that the
238 /// wait must end. Lock will be reacquired when the wait exits.
239 /// Spurious wakes may happen before the time point is reached. In
240 /// such cases the predicate is invoked and it must return `false`
241 /// for the wait to continue. The predicate will be invoked with
242 /// the mutex locked.
243 ///
244 /// @note Since the predicate is invoked with the mutex locked, if it
245 /// accesses other guarded resources, the predicate itself must be
246 /// decorated with the IPLR_REQUIRES directive. For instance,
247 ///
248 /// ```c++
249 /// [] () IPLR_REQUIRES(mutex) {
250 /// return my_guarded_resource.should_stop_waiting;
251 /// }
252 /// ```
253 ///
254 /// @param mutex The mutex
255 /// @param[in] should_stop_waiting The should stop waiting
256 ///
257 void Wait(Mutex& mutex, const Predicate& should_stop_waiting)
258 IPLR_REQUIRES(mutex) {
259 std::unique_lock lock(mutex.mutex_, std::adopt_lock);
260 cv_.wait(lock, should_stop_waiting);
261 lock.release();
262 }
263
264 private:
265 std::condition_variable cv_;
266 };
267
268 } // namespace impeller
269
270 #endif // FLUTTER_IMPELLER_BASE_THREAD_H_
impeller::Lock::Lock
Lock(Mutex &mutex) IPLR_ACQUIRE(mutex)
Definition: thread.h:74
impeller::ReaderLock::~ReaderLock
~ReaderLock() IPLR_RELEASE()
Definition: thread.h:99
impeller::Lock::~Lock
~Lock() IPLR_RELEASE()
Definition: thread.h:78
IPLR_ACQUIRE_SHARED
#define IPLR_ACQUIRE_SHARED(...)
Definition: thread_safety.h:39
IPLR_SCOPED_CAPABILITY
#define IPLR_SCOPED_CAPABILITY
Definition: thread_safety.h:16
impeller::WriterLock
Definition: thread.h:113
impeller::Lock
Definition: thread.h:72
impeller::ConditionVariable::NotifyAll
void NotifyAll()
Definition: thread.h:155
impeller::WriterLock::WriterLock
WriterLock(RWMutex &mutex) IPLR_ACQUIRE(mutex)
Definition: thread.h:115
impeller::ConditionVariable::Wait
void Wait(Mutex &mutex, const Predicate &should_stop_waiting) IPLR_REQUIRES(mutex)
Atomically unlocks the mutex and waits on the condition variable indefinitely till the predicate dete...
Definition: thread.h:257
impeller::ReaderLock::ReaderLock
ReaderLock(RWMutex &mutex) IPLR_ACQUIRE_SHARED(mutex)
Definition: thread.h:94
IPLR_ACQUIRE
#define IPLR_ACQUIRE(...)
Definition: thread_safety.h:36
impeller::ConditionVariable::ConditionVariable
ConditionVariable()=default
IPLR_RELEASE
#define IPLR_RELEASE(...)
Definition: thread_safety.h:42
impeller::ReaderLock
Definition: thread.h:92
thread_safety.h
impeller::WriterLock::~WriterLock
~WriterLock() IPLR_RELEASE()
Definition: thread.h:119
impeller::ConditionVariable::Predicate
std::function< bool()> Predicate
Definition: thread.h:157
impeller::ConditionVariable::operator=
ConditionVariable & operator=(const ConditionVariable &)=delete
impeller::ConditionVariable::NotifyOne
void NotifyOne()
Definition: thread.h:153
impeller::ConditionVariable::~ConditionVariable
~ConditionVariable()=default
impeller::IPLR_CAPABILITY
class IPLR_CAPABILITY("mutex") Mutex
Definition: thread.h:22
IPLR_RELEASE_SHARED
#define IPLR_RELEASE_SHARED(...)
Definition: thread_safety.h:45
impeller::ConditionVariable
A condition variable exactly similar to the one in libcxx with two major differences:
Definition: thread.h:143
impeller::ConditionVariable::WaitUntil
bool WaitUntil(Mutex &mutex, const std::chrono::time_point< Clock, Duration > &time_point, const Predicate &should_stop_waiting) IPLR_REQUIRES(mutex)
Atomically unlocks the mutex and waits on the condition variable up to a specified time point....
Definition: thread.h:189
impeller::ConditionVariable::WaitFor
bool WaitFor(Mutex &mutex, const std::chrono::duration< Representation, Period > &duration, const Predicate &should_stop_waiting) IPLR_REQUIRES(mutex)
Atomically unlocks the mutex and waits on the condition variable for a designated duration....
Definition: thread.h:228
impeller
Definition: allocation.cc:12
IPLR_REQUIRES
#define IPLR_REQUIRES(...)
Definition: thread_safety.h:30