OLD | NEW |
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/cond_var.h" | 5 #include "mojo/edk/util/cond_var.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <time.h> | 9 #include <time.h> |
10 | 10 |
11 #include <limits> | 11 #include <limits> |
12 | 12 |
13 #include "base/logging.h" | |
14 #include "build/build_config.h" | 13 #include "build/build_config.h" |
15 #include "mojo/edk/system/mutex.h" | 14 #include "mojo/edk/util/logging_internal.h" |
| 15 #include "mojo/edk/util/mutex.h" |
16 | 16 |
17 namespace mojo { | 17 namespace mojo { |
18 namespace system { | 18 namespace util { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 // Helper for |CondVar::WaitWithTimeout()|. Returns true on (definite) time-out. | 22 // Helper for |CondVar::WaitWithTimeout()|. Returns true on (definite) time-out. |
23 bool RelativeTimedWait(const struct timespec& timeout_rel, | 23 bool RelativeTimedWait(const struct timespec& timeout_rel, |
24 pthread_cond_t* posix_cond_var, | 24 pthread_cond_t* posix_cond_var, |
25 pthread_mutex_t* posix_mutex) { | 25 pthread_mutex_t* posix_mutex) { |
26 // Mac has a function to do a relative timed wait directly. | 26 // Mac has a function to do a relative timed wait directly. |
27 #if defined(OS_MACOSX) | 27 #if defined(OS_MACOSX) |
28 int error = pthread_cond_timedwait_relative_np(posix_cond_var, posix_mutex, | 28 int error = pthread_cond_timedwait_relative_np(posix_cond_var, posix_mutex, |
29 &timeout_rel); | 29 &timeout_rel); |
30 DCHECK(error == 0 || error == ETIMEDOUT || error == EINTR) | 30 INTERNAL_DCHECK_WITH_ERRNO(error == 0 || error == ETIMEDOUT || error == EINTR, |
31 << ". pthread_cond_timedwait_relative_np: " << strerror(error); | 31 "pthread_cond_timedwait_relative_np", error); |
32 return error == ETIMEDOUT; | 32 return error == ETIMEDOUT; |
33 #else | 33 #else |
34 static const long kNanosecondsPerSecond = 1000000000L; | 34 static const long kNanosecondsPerSecond = 1000000000L; |
35 | 35 |
36 // NaCl's |pthread_condattr_setclock()| only supports |CLOCK_REALTIME| (which is | 36 // NaCl's |pthread_condattr_setclock()| only supports |CLOCK_REALTIME| (which is |
37 // the default, which is why we don't bother setting it in |CondVar|'s | 37 // the default, which is why we don't bother setting it in |CondVar|'s |
38 // constructor). | 38 // constructor). |
39 #if defined(OS_NACL) | 39 #if defined(OS_NACL) |
40 static const clockid_t kClockType = CLOCK_REALTIME; | 40 static const clockid_t kClockType = CLOCK_REALTIME; |
41 #else | 41 #else |
42 static const clockid_t kClockType = CLOCK_MONOTONIC; | 42 static const clockid_t kClockType = CLOCK_MONOTONIC; |
43 #endif // defined(OS_NACL) | 43 #endif // defined(OS_NACL) |
44 | 44 |
45 struct timespec timeout_abs; | 45 struct timespec timeout_abs; |
46 int error = clock_gettime(kClockType, &timeout_abs); | 46 int error = clock_gettime(kClockType, &timeout_abs); |
47 // Note: The return value of |clock_gettime()| is *not* an error code, unlike | 47 // Note: The return value of |clock_gettime()| is *not* an error code, unlike |
48 // the pthreads functions. | 48 // the pthreads functions (however, it sets errno). |
49 DPCHECK(!error) << "clock_gettime"; | 49 INTERNAL_DCHECK_WITH_ERRNO(!error, "clock_gettime", errno); |
50 | 50 |
51 timeout_abs.tv_sec += timeout_rel.tv_sec; | 51 timeout_abs.tv_sec += timeout_rel.tv_sec; |
52 timeout_abs.tv_nsec += timeout_rel.tv_nsec; | 52 timeout_abs.tv_nsec += timeout_rel.tv_nsec; |
53 if (timeout_abs.tv_nsec >= kNanosecondsPerSecond) { | 53 if (timeout_abs.tv_nsec >= kNanosecondsPerSecond) { |
54 timeout_abs.tv_sec++; | 54 timeout_abs.tv_sec++; |
55 timeout_abs.tv_nsec -= kNanosecondsPerSecond; | 55 timeout_abs.tv_nsec -= kNanosecondsPerSecond; |
56 DCHECK_LT(timeout_abs.tv_nsec, kNanosecondsPerSecond); | 56 INTERNAL_DCHECK(timeout_abs.tv_nsec < kNanosecondsPerSecond); |
57 } | 57 } |
58 | 58 |
59 // Older Android doesn't have |pthread_condattr_setclock()|, but they have | 59 // Older Android doesn't have |pthread_condattr_setclock()|, but they have |
60 // |pthread_cond_timedwait_monotonic_np()|. | 60 // |pthread_cond_timedwait_monotonic_np()|. |
61 #if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) | 61 #if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) |
62 error = pthread_cond_timedwait_monotonic_np(posix_cond_var, posix_mutex, | 62 error = pthread_cond_timedwait_monotonic_np(posix_cond_var, posix_mutex, |
63 &timeout_abs); | 63 &timeout_abs); |
64 DCHECK(error == 0 || error == ETIMEDOUT || error == EINTR) | 64 INTERNAL_DCHECK_WITH_ERRNO(error == 0 || error == ETIMEDOUT || error == EINTR, |
65 << ". pthread_cond_timedwait_monotonic_np: " << strerror(error); | 65 "pthread_cond_timedwait_monotonic_np", error); |
66 #else | 66 #else |
67 error = pthread_cond_timedwait(posix_cond_var, posix_mutex, &timeout_abs); | 67 error = pthread_cond_timedwait(posix_cond_var, posix_mutex, &timeout_abs); |
68 DCHECK(error == 0 || error == ETIMEDOUT || error == EINTR) | 68 INTERNAL_DCHECK_WITH_ERRNO(error == 0 || error == ETIMEDOUT || error == EINTR, |
69 << ". pthread_cond_timedwait: " << strerror(error); | 69 "pthread_cond_timedwait", error); |
70 #endif // defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) | 70 #endif // defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) |
71 return error == ETIMEDOUT; | 71 return error == ETIMEDOUT; |
72 #endif // defined(OS_MACOSX) | 72 #endif // defined(OS_MACOSX) |
73 } | 73 } |
74 | 74 |
75 } // namespace | 75 } // namespace |
76 | 76 |
77 CondVar::CondVar() { | 77 CondVar::CondVar() { |
78 // Mac and older Android don't have |pthread_condattr_setclock()| (but they have | 78 // Mac and older Android don't have |pthread_condattr_setclock()| (but they have |
79 // other timed wait functions we can use) and NaCl doesn't have a useful one. | 79 // other timed wait functions we can use) and NaCl doesn't have a useful one. |
80 #if !defined(OS_MACOSX) && !defined(OS_NACL) && \ | 80 #if !defined(OS_MACOSX) && !defined(OS_NACL) && \ |
81 !(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) | 81 !(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) |
82 pthread_condattr_t attr; | 82 pthread_condattr_t attr; |
83 int error = pthread_condattr_init(&attr); | 83 int error = pthread_condattr_init(&attr); |
84 DCHECK(!error) << "pthread_condattr_init: " << strerror(error); | 84 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_condattr_init", error); |
85 error = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); | 85 error = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); |
86 DCHECK(!error) << "pthread_condattr_setclock: " << strerror(error); | 86 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_condattr_setclock", error); |
87 error = pthread_cond_init(&impl_, &attr); | 87 error = pthread_cond_init(&impl_, &attr); |
88 DCHECK(!error) << "pthread_cond_init: " << strerror(error); | 88 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_cond_init", error); |
89 error = pthread_condattr_destroy(&attr); | 89 error = pthread_condattr_destroy(&attr); |
90 DCHECK(!error) << "pthread_condattr_destroy: " << strerror(error); | 90 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_condattr_destroy", error); |
91 #else | 91 #else |
92 int error = pthread_cond_init(&impl_, nullptr); | 92 int error = pthread_cond_init(&impl_, nullptr); |
93 DCHECK(!error) << "pthread_cond_init: " << strerror(error); | 93 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_cond_init", error); |
94 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !(defined(OS_ANDROID)...) | 94 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !(defined(OS_ANDROID)...) |
95 } | 95 } |
96 | 96 |
97 CondVar::~CondVar() { | 97 CondVar::~CondVar() { |
98 int error = pthread_cond_destroy(&impl_); | 98 int error = pthread_cond_destroy(&impl_); |
99 DCHECK(!error) << "pthread_cond_destroy: " << strerror(error); | 99 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_cond_destroy", error); |
100 } | 100 } |
101 | 101 |
102 void CondVar::Wait(Mutex* mutex) { | 102 void CondVar::Wait(Mutex* mutex) { |
103 DCHECK(mutex); | 103 INTERNAL_DCHECK(mutex); |
104 mutex->AssertHeld(); | 104 mutex->AssertHeld(); |
105 | 105 |
106 int error = pthread_cond_wait(&impl_, &mutex->impl_); | 106 int error = pthread_cond_wait(&impl_, &mutex->impl_); |
107 DCHECK(!error) << "pthread_cond_wait: " << strerror(error); | 107 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_cond_wait", error); |
108 } | 108 } |
109 | 109 |
110 bool CondVar::WaitWithTimeout(Mutex* mutex, uint64_t timeout_microseconds) { | 110 bool CondVar::WaitWithTimeout(Mutex* mutex, uint64_t timeout_microseconds) { |
111 static const uint64_t kMicrosecondsPerSecond = 1000000ULL; | 111 static const uint64_t kMicrosecondsPerSecond = 1000000ULL; |
112 static const uint64_t kNanosecondsPerMicrosecond = 1000ULL; | 112 static const uint64_t kNanosecondsPerMicrosecond = 1000ULL; |
113 | 113 |
114 // Turn very long waits into "forever". This isn't a huge concern if |time_t| | 114 // Turn very long waits into "forever". This isn't a huge concern if |time_t| |
115 // is 64-bit, but overflowing |time_t| is a real risk if it's only 32-bit. | 115 // is 64-bit, but overflowing |time_t| is a real risk if it's only 32-bit. |
116 // (2^31 / 16 seconds = ~4.25 years, so we won't risk overflowing until 2033.) | 116 // (2^31 / 16 seconds = ~4.25 years, so we won't risk overflowing until 2033.) |
117 constexpr uint64_t kForeverThresholdSeconds = | 117 constexpr uint64_t kForeverThresholdSeconds = |
118 std::numeric_limits<time_t>::max() / 16; | 118 std::numeric_limits<time_t>::max() / 16; |
119 uint64_t timeout_seconds = timeout_microseconds / kMicrosecondsPerSecond; | 119 uint64_t timeout_seconds = timeout_microseconds / kMicrosecondsPerSecond; |
120 if (timeout_seconds >= kForeverThresholdSeconds) { | 120 if (timeout_seconds >= kForeverThresholdSeconds) { |
121 Wait(mutex); | 121 Wait(mutex); |
122 return false; // Did *not* time out. | 122 return false; // Did *not* time out. |
123 } | 123 } |
124 | 124 |
125 DCHECK(mutex); | 125 INTERNAL_DCHECK(mutex); |
126 mutex->AssertHeld(); | 126 mutex->AssertHeld(); |
127 | 127 |
128 struct timespec timeout_rel = {}; | 128 struct timespec timeout_rel = {}; |
129 timeout_rel.tv_sec = static_cast<time_t>(timeout_seconds); | 129 timeout_rel.tv_sec = static_cast<time_t>(timeout_seconds); |
130 timeout_rel.tv_nsec = | 130 timeout_rel.tv_nsec = |
131 static_cast<long>((timeout_microseconds % kMicrosecondsPerSecond) * | 131 static_cast<long>((timeout_microseconds % kMicrosecondsPerSecond) * |
132 kNanosecondsPerMicrosecond); | 132 kNanosecondsPerMicrosecond); |
133 return RelativeTimedWait(timeout_rel, &impl_, &mutex->impl_); | 133 return RelativeTimedWait(timeout_rel, &impl_, &mutex->impl_); |
134 } | 134 } |
135 | 135 |
136 void CondVar::Signal() { | 136 void CondVar::Signal() { |
137 int error = pthread_cond_signal(&impl_); | 137 int error = pthread_cond_signal(&impl_); |
138 DCHECK(!error) << "pthread_cond_signal: " << strerror(error); | 138 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_cond_signal", error); |
139 } | 139 } |
140 | 140 |
141 void CondVar::SignalAll() { | 141 void CondVar::SignalAll() { |
142 int error = pthread_cond_broadcast(&impl_); | 142 int error = pthread_cond_broadcast(&impl_); |
143 DCHECK(!error) << "pthread_cond_broadcast: " << strerror(error); | 143 INTERNAL_DCHECK_WITH_ERRNO(!error, "pthread_cond_broadcast", error); |
144 } | 144 } |
145 | 145 |
146 } // namespace system | 146 } // namespace util |
147 } // namespace mojo | 147 } // namespace mojo |
OLD | NEW |