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