Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: mojo/edk/system/waitable_event.cc

Issue 1408003013: Reland "EDK: Move //mojo/edk/system/waitable_event* to edk/util." (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/edk/system/waitable_event.h ('k') | mojo/edk/system/waitable_event_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium 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 "mojo/edk/system/waitable_event.h"
6
7 #include "base/logging.h"
8 #include "base/time/time.h"
9
10 using mojo::util::CondVar;
11 using mojo::util::Mutex;
12 using mojo::util::MutexLocker;
13
14 namespace mojo {
15 namespace system {
16
17 namespace {
18
19 // Waits with a timeout on |condition()|. Returns true on timeout, or false if
20 // |condition()| ever returns true. |condition()| should have no side effects
21 // (and will always be called with |*mutex| held).
22 template <typename ConditionFn>
23 bool WaitWithTimeoutImpl(Mutex* mutex,
24 CondVar* cv,
25 ConditionFn condition,
26 uint64_t timeout_microseconds)
27 MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex) {
28 mutex->AssertHeld();
29
30 if (condition())
31 return false;
32
33 // We may get spurious wakeups.
34 uint64_t wait_remaining = timeout_microseconds;
35 auto start = base::TimeTicks::Now();
36 while (true) {
37 if (cv->WaitWithTimeout(mutex, wait_remaining))
38 return true; // Definitely timed out.
39
40 // We may have been awoken.
41 if (condition())
42 return false;
43
44 // Or the wakeup may have been spurious.
45 auto now = base::TimeTicks::Now();
46 DCHECK_GE(now, start);
47 uint64_t elapsed = static_cast<uint64_t>((now - start).InMicroseconds());
48 // It's possible that we may have timed out anyway.
49 if (elapsed >= timeout_microseconds)
50 return true;
51
52 // Otherwise, recalculate the amount that we have left to wait.
53 wait_remaining = timeout_microseconds - elapsed;
54 }
55 }
56
57 } // namespace
58
59 // AutoResetWaitableEvent ------------------------------------------------------
60
61 void AutoResetWaitableEvent::Signal() {
62 MutexLocker locker(&mutex_);
63 signaled_ = true;
64 cv_.Signal();
65 }
66
67 void AutoResetWaitableEvent::Reset() {
68 MutexLocker locker(&mutex_);
69 signaled_ = false;
70 }
71
72 void AutoResetWaitableEvent::Wait() {
73 MutexLocker locker(&mutex_);
74 while (!signaled_)
75 cv_.Wait(&mutex_);
76 signaled_ = false;
77 }
78
79 bool AutoResetWaitableEvent::WaitWithTimeout(uint64_t timeout_microseconds) {
80 MutexLocker locker(&mutex_);
81
82 if (signaled_) {
83 signaled_ = false;
84 return false;
85 }
86
87 // We may get spurious wakeups.
88 uint64_t wait_remaining = timeout_microseconds;
89 auto start = base::TimeTicks::Now();
90 while (true) {
91 if (cv_.WaitWithTimeout(&mutex_, wait_remaining))
92 return true; // Definitely timed out.
93
94 // We may have been awoken.
95 if (signaled_)
96 break;
97
98 // Or the wakeup may have been spurious.
99 auto now = base::TimeTicks::Now();
100 DCHECK_GE(now, start);
101 uint64_t elapsed = static_cast<uint64_t>((now - start).InMicroseconds());
102 // It's possible that we may have timed out anyway.
103 if (elapsed >= timeout_microseconds)
104 return true;
105
106 // Otherwise, recalculate the amount that we have left to wait.
107 wait_remaining = timeout_microseconds - elapsed;
108 }
109
110 signaled_ = false;
111 return false;
112 }
113
114 bool AutoResetWaitableEvent::IsSignaledForTest() {
115 MutexLocker locker(&mutex_);
116 return signaled_;
117 }
118
119 // ManualResetWaitableEvent ----------------------------------------------------
120
121 void ManualResetWaitableEvent::Signal() {
122 MutexLocker locker(&mutex_);
123 signaled_ = true;
124 signal_id_++;
125 cv_.SignalAll();
126 }
127
128 void ManualResetWaitableEvent::Reset() {
129 MutexLocker locker(&mutex_);
130 signaled_ = false;
131 }
132
133 void ManualResetWaitableEvent::Wait() {
134 MutexLocker locker(&mutex_);
135
136 if (signaled_)
137 return;
138
139 auto last_signal_id = signal_id_;
140 do {
141 cv_.Wait(&mutex_);
142 } while (signal_id_ == last_signal_id);
143 }
144
145 bool ManualResetWaitableEvent::WaitWithTimeout(uint64_t timeout_microseconds) {
146 MutexLocker locker(&mutex_);
147
148 auto last_signal_id = signal_id_;
149 // Disable thread-safety analysis for the lambda: We could annotate it with
150 // |MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_)|, but then the analyzer currently
151 // isn't able to figure out that |WaitWithTimeoutImpl()| calls it while
152 // holding |mutex_|.
153 bool rv = WaitWithTimeoutImpl(
154 &mutex_, &cv_, [this, last_signal_id]() MOJO_NO_THREAD_SAFETY_ANALYSIS {
155 // Also check |signaled_| in case we're already signaled.
156 return signaled_ || signal_id_ != last_signal_id;
157 }, timeout_microseconds);
158 DCHECK(rv || signaled_ || signal_id_ != last_signal_id);
159 return rv;
160 }
161
162 bool ManualResetWaitableEvent::IsSignaledForTest() {
163 MutexLocker locker(&mutex_);
164 return signaled_;
165 }
166
167 } // namespace system
168 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/system/waitable_event.h ('k') | mojo/edk/system/waitable_event_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698