Flutter Engine
The Flutter Engine
waitable_event.cc
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#include "flutter/fml/synchronization/waitable_event.h"
6
7#include <cerrno>
8#include <ctime>
9
10#include "flutter/fml/logging.h"
11#include "flutter/fml/time/time_delta.h"
12#include "flutter/fml/time/time_point.h"
13
14namespace fml {
15
16// Waits with a timeout on |condition()|. Returns true on timeout, or false if
17// |condition()| ever returns true. |condition()| should have no side effects
18// (and will always be called with |*mutex| held).
19template <typename ConditionFn>
20bool WaitWithTimeoutImpl(std::unique_lock<std::mutex>* locker,
21 std::condition_variable* cv,
22 ConditionFn condition,
24 FML_DCHECK(locker->owns_lock());
25
26 if (condition()) {
27 return false;
28 }
29
30 // We may get spurious wakeups.
31 TimeDelta wait_remaining = timeout;
33 while (true) {
35 cv->wait_for(*locker, std::chrono::nanoseconds(
36 wait_remaining.ToNanoseconds()))) {
37 return true; // Definitely timed out.
38 }
39
40 // We may have been awoken.
41 if (condition()) {
42 return false;
43 }
44
45 // Or the wakeup may have been spurious.
47 FML_DCHECK(now >= start);
48 TimeDelta elapsed = now - start;
49 // It's possible that we may have timed out anyway.
50 if (elapsed >= timeout) {
51 return true;
52 }
53
54 // Otherwise, recalculate the amount that we have left to wait.
55 wait_remaining = timeout - elapsed;
56 }
57}
58
59// AutoResetWaitableEvent ------------------------------------------------------
60
62 std::scoped_lock locker(mutex_);
63 signaled_ = true;
64 cv_.notify_one();
65}
66
68 std::scoped_lock locker(mutex_);
69 signaled_ = false;
70}
71
73 std::unique_lock<std::mutex> locker(mutex_);
74 while (!signaled_) {
75 cv_.wait(locker);
76 }
77 signaled_ = false;
78}
79
81 std::unique_lock<std::mutex> locker(mutex_);
82
83 if (signaled_) {
84 signaled_ = false;
85 return false;
86 }
87
88 // We may get spurious wakeups.
89 TimeDelta wait_remaining = timeout;
91 while (true) {
93 cv_.wait_for(
94 locker, std::chrono::nanoseconds(wait_remaining.ToNanoseconds()))) {
95 return true; // Definitely timed out.
96 }
97
98 // We may have been awoken.
99 if (signaled_) {
100 break;
101 }
102
103 // Or the wakeup may have been spurious.
105 FML_DCHECK(now >= start);
106 TimeDelta elapsed = now - start;
107 // It's possible that we may have timed out anyway.
108 if (elapsed >= timeout) {
109 return true;
110 }
111
112 // Otherwise, recalculate the amount that we have left to wait.
113 wait_remaining = timeout - elapsed;
114 }
115
116 signaled_ = false;
117 return false;
118}
119
121 std::scoped_lock locker(mutex_);
122 return signaled_;
123}
124
125// ManualResetWaitableEvent ----------------------------------------------------
126
128 std::scoped_lock locker(mutex_);
129 signaled_ = true;
130 signal_id_++;
131 cv_.notify_all();
132}
133
135 std::scoped_lock locker(mutex_);
136 signaled_ = false;
137}
138
140 std::unique_lock<std::mutex> locker(mutex_);
141
142 if (signaled_) {
143 return;
144 }
145
146 auto last_signal_id = signal_id_;
147 do {
148 cv_.wait(locker);
149 } while (signal_id_ == last_signal_id);
150}
151
153 std::unique_lock<std::mutex> locker(mutex_);
154
155 auto last_signal_id = signal_id_;
156 // Disable thread-safety analysis for the lambda: We could annotate it with
157 // |FML_EXCLUSIVE_LOCKS_REQUIRED(mutex_)|, but then the analyzer currently
158 // isn't able to figure out that |WaitWithTimeoutImpl()| calls it while
159 // holding |mutex_|.
160 bool rv = WaitWithTimeoutImpl(
161 &locker, &cv_,
162 [this, last_signal_id]() {
163 // Also check |signaled_| in case we're already signaled.
164 return signaled_ || signal_id_ != last_signal_id;
165 },
166 timeout);
167 FML_DCHECK(rv || signaled_ || signal_id_ != last_signal_id);
168 return rv;
169}
170
172 std::scoped_lock locker(mutex_);
173 return signaled_;
174}
175
176} // namespace fml
bool WaitWithTimeout(TimeDelta timeout)
bool WaitWithTimeout(TimeDelta timeout)
constexpr int64_t ToNanoseconds() const
Definition: time_delta.h:61
static TimePoint Now()
Definition: time_point.cc:49
#define FML_DCHECK(condition)
Definition: logging.h:103
Definition: ascii_trie.cc:9
bool WaitWithTimeoutImpl(std::unique_lock< std::mutex > *locker, std::condition_variable *cv, ConditionFn condition, TimeDelta timeout)
def timeout(deadline, cmd)