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

Side by Side Diff: mojo/edk/util/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/util/waitable_event.h ('k') | mojo/edk/util/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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/edk/system/waitable_event.h" 5 #include "mojo/edk/util/waitable_event.h"
6 6
7 #include "base/logging.h" 7 #include "build/build_config.h"
8 #include "base/time/time.h" 8 #include "mojo/edk/util/logging_internal.h"
9 9
10 using mojo::util::CondVar; 10 #if defined(OS_MACOSX) || defined(OS_IOS)
11 using mojo::util::Mutex; 11 #include <mach/kern_return.h>
12 using mojo::util::MutexLocker; 12 #include <mach/mach_time.h>
13 #else
14 #include <errno.h>
15 #include <time.h>
16 #endif // defined(OS_MACOSX) || defined(OS_IOS)
13 17
14 namespace mojo { 18 namespace mojo {
15 namespace system { 19 namespace util {
16 20
17 namespace { 21 namespace {
18 22
23 // Mac OS X/iOS don't have a (useful) |clock_gettime()|.
24 // Note: Chromium's |base::TimeTicks::Now()| uses boot time (obtained via
25 // |sysctl()| with |CTL_KERN|/|KERN_BOOTTIME|). For our current purposes,
26 // monotonic time (which pauses during sleeps) is sufficient. TODO(vtl): If/when
27 // we use this for other purposes, maybe we should use boot time (maybe also on
28 // POSIX).
29 #if defined(OS_MACOSX) || defined(OS_IOS)
30 mach_timebase_info_data_t GetMachTimebaseInfo() {
31 mach_timebase_info_data_t timebase_info = {};
32 kern_return_t error = mach_timebase_info(&timebase_info);
33 INTERNAL_DCHECK(error == KERN_SUCCESS);
34 return timebase_info;
35 }
36
37 // Returns the number of microseconds elapsed since epoch start (according to a
38 // monotonic clock).
39 uint64_t Now() {
40 const uint64_t kNanosecondsPerMicrosecond = 1000ULL;
41
42 // TODO(vtl): Without magic statics, this is not thread-safe, at least the
43 // first time around (neither is Mac Chromium's |base::TimeTicks::Now()|)!
44 static mach_timebase_info_data_t timebase_info = GetMachTimebaseInfo();
45
46 // |timebase_info| converts absolute time tick units into nanoseconds. By
47 // dividing by 1000 first, we reduce the risk of overflowing (at the cost of a
48 // risk of a slight loss in precision).
49 return mach_absolute_time() / kNanosecondsPerMicrosecond *
50 timebase_info.numer / timebase_info.denom;
51 }
52 #else
53 // Returns the number of microseconds elapsed since epoch start (according to a
54 // monotonic clock).
55 uint64_t Now() {
56 const uint64_t kMicrosecondsPerSecond = 1000000ULL;
57 const uint64_t kNanosecondsPerMicrosecond = 1000ULL;
58
59 struct timespec now;
60 int error = clock_gettime(CLOCK_MONOTONIC, &now);
61 INTERNAL_DCHECK_WITH_ERRNO(!error, "clock_gettime", errno);
62 INTERNAL_DCHECK(now.tv_sec >= 0);
63 INTERNAL_DCHECK(now.tv_nsec >= 0);
64
65 return static_cast<uint64_t>(now.tv_sec) * kMicrosecondsPerSecond +
66 static_cast<uint64_t>(now.tv_nsec) / kNanosecondsPerMicrosecond;
67 }
68 #endif // defined(OS_MACOSX) || defined(OS_IOS)
69
19 // Waits with a timeout on |condition()|. Returns true on timeout, or false if 70 // Waits with a timeout on |condition()|. Returns true on timeout, or false if
20 // |condition()| ever returns true. |condition()| should have no side effects 71 // |condition()| ever returns true. |condition()| should have no side effects
21 // (and will always be called with |*mutex| held). 72 // (and will always be called with |*mutex| held).
22 template <typename ConditionFn> 73 template <typename ConditionFn>
23 bool WaitWithTimeoutImpl(Mutex* mutex, 74 bool WaitWithTimeoutImpl(Mutex* mutex,
24 CondVar* cv, 75 CondVar* cv,
25 ConditionFn condition, 76 ConditionFn condition,
26 uint64_t timeout_microseconds) 77 uint64_t timeout_microseconds)
27 MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex) { 78 MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex) {
28 mutex->AssertHeld(); 79 mutex->AssertHeld();
29 80
30 if (condition()) 81 if (condition())
31 return false; 82 return false;
32 83
33 // We may get spurious wakeups. 84 // We may get spurious wakeups.
34 uint64_t wait_remaining = timeout_microseconds; 85 uint64_t wait_remaining = timeout_microseconds;
35 auto start = base::TimeTicks::Now(); 86 uint64_t start = Now();
36 while (true) { 87 while (true) {
37 if (cv->WaitWithTimeout(mutex, wait_remaining)) 88 if (cv->WaitWithTimeout(mutex, wait_remaining))
38 return true; // Definitely timed out. 89 return true; // Definitely timed out.
39 90
40 // We may have been awoken. 91 // We may have been awoken.
41 if (condition()) 92 if (condition())
42 return false; 93 return false;
43 94
44 // Or the wakeup may have been spurious. 95 // Or the wakeup may have been spurious.
45 auto now = base::TimeTicks::Now(); 96 uint64_t now = Now();
46 DCHECK_GE(now, start); 97 INTERNAL_DCHECK(now >= start);
47 uint64_t elapsed = static_cast<uint64_t>((now - start).InMicroseconds()); 98 uint64_t elapsed = now - start;
48 // It's possible that we may have timed out anyway. 99 // It's possible that we may have timed out anyway.
49 if (elapsed >= timeout_microseconds) 100 if (elapsed >= timeout_microseconds)
50 return true; 101 return true;
51 102
52 // Otherwise, recalculate the amount that we have left to wait. 103 // Otherwise, recalculate the amount that we have left to wait.
53 wait_remaining = timeout_microseconds - elapsed; 104 wait_remaining = timeout_microseconds - elapsed;
54 } 105 }
55 } 106 }
56 107
57 } // namespace 108 } // namespace
(...skipping 21 matching lines...) Expand all
79 bool AutoResetWaitableEvent::WaitWithTimeout(uint64_t timeout_microseconds) { 130 bool AutoResetWaitableEvent::WaitWithTimeout(uint64_t timeout_microseconds) {
80 MutexLocker locker(&mutex_); 131 MutexLocker locker(&mutex_);
81 132
82 if (signaled_) { 133 if (signaled_) {
83 signaled_ = false; 134 signaled_ = false;
84 return false; 135 return false;
85 } 136 }
86 137
87 // We may get spurious wakeups. 138 // We may get spurious wakeups.
88 uint64_t wait_remaining = timeout_microseconds; 139 uint64_t wait_remaining = timeout_microseconds;
89 auto start = base::TimeTicks::Now(); 140 uint64_t start = Now();
90 while (true) { 141 while (true) {
91 if (cv_.WaitWithTimeout(&mutex_, wait_remaining)) 142 if (cv_.WaitWithTimeout(&mutex_, wait_remaining))
92 return true; // Definitely timed out. 143 return true; // Definitely timed out.
93 144
94 // We may have been awoken. 145 // We may have been awoken.
95 if (signaled_) 146 if (signaled_)
96 break; 147 break;
97 148
98 // Or the wakeup may have been spurious. 149 // Or the wakeup may have been spurious.
99 auto now = base::TimeTicks::Now(); 150 uint64_t now = Now();
100 DCHECK_GE(now, start); 151 INTERNAL_DCHECK(now >= start);
101 uint64_t elapsed = static_cast<uint64_t>((now - start).InMicroseconds()); 152 uint64_t elapsed = now - start;
102 // It's possible that we may have timed out anyway. 153 // It's possible that we may have timed out anyway.
103 if (elapsed >= timeout_microseconds) 154 if (elapsed >= timeout_microseconds)
104 return true; 155 return true;
105 156
106 // Otherwise, recalculate the amount that we have left to wait. 157 // Otherwise, recalculate the amount that we have left to wait.
107 wait_remaining = timeout_microseconds - elapsed; 158 wait_remaining = timeout_microseconds - elapsed;
108 } 159 }
109 160
110 signaled_ = false; 161 signaled_ = false;
111 return false; 162 return false;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 auto last_signal_id = signal_id_; 199 auto last_signal_id = signal_id_;
149 // Disable thread-safety analysis for the lambda: We could annotate it with 200 // Disable thread-safety analysis for the lambda: We could annotate it with
150 // |MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_)|, but then the analyzer currently 201 // |MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_)|, but then the analyzer currently
151 // isn't able to figure out that |WaitWithTimeoutImpl()| calls it while 202 // isn't able to figure out that |WaitWithTimeoutImpl()| calls it while
152 // holding |mutex_|. 203 // holding |mutex_|.
153 bool rv = WaitWithTimeoutImpl( 204 bool rv = WaitWithTimeoutImpl(
154 &mutex_, &cv_, [this, last_signal_id]() MOJO_NO_THREAD_SAFETY_ANALYSIS { 205 &mutex_, &cv_, [this, last_signal_id]() MOJO_NO_THREAD_SAFETY_ANALYSIS {
155 // Also check |signaled_| in case we're already signaled. 206 // Also check |signaled_| in case we're already signaled.
156 return signaled_ || signal_id_ != last_signal_id; 207 return signaled_ || signal_id_ != last_signal_id;
157 }, timeout_microseconds); 208 }, timeout_microseconds);
158 DCHECK(rv || signaled_ || signal_id_ != last_signal_id); 209 INTERNAL_DCHECK(rv || signaled_ || signal_id_ != last_signal_id);
159 return rv; 210 return rv;
160 } 211 }
161 212
162 bool ManualResetWaitableEvent::IsSignaledForTest() { 213 bool ManualResetWaitableEvent::IsSignaledForTest() {
163 MutexLocker locker(&mutex_); 214 MutexLocker locker(&mutex_);
164 return signaled_; 215 return signaled_;
165 } 216 }
166 217
167 } // namespace system 218 } // namespace util
168 } // namespace mojo 219 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/util/waitable_event.h ('k') | mojo/edk/util/waitable_event_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698