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