condition_variable_posix.cc (3738B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #include "base/condition_variable.h" 8 9 #include <errno.h> 10 #include <stdint.h> 11 #include <sys/time.h> 12 13 #include "base/lock.h" 14 #include "base/logging.h" 15 #include "base/time.h" 16 17 ConditionVariable::ConditionVariable(Lock* user_lock) 18 : user_mutex_(user_lock->lock_.native_handle()) { 19 int rv = 0; 20 // http://crbug.com/293736 21 // On older Android platform versions, monotonic clock based absolute 22 // deadlines are supported through the non-standard 23 // pthread_cond_timedwait_monotonic_np. Newer platform versions have 24 // pthread_condattr_setclock. 25 // Mac can use relative time deadlines. 26 #if !defined(XP_DARWIN) && \ 27 !(defined(ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) 28 pthread_condattr_t attrs; 29 rv = pthread_condattr_init(&attrs); 30 DCHECK_EQ(0, rv); 31 pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); 32 rv = pthread_cond_init(&condition_, &attrs); 33 pthread_condattr_destroy(&attrs); 34 #else 35 rv = pthread_cond_init(&condition_, NULL); 36 #endif 37 DCHECK_EQ(0, rv); 38 } 39 40 ConditionVariable::~ConditionVariable() { 41 #if defined(XP_DARWIN) 42 // This hack is necessary to avoid a fatal pthreads subsystem bug in the 43 // Darwin kernel. http://crbug.com/517681. 44 { 45 Lock lock; 46 AutoLock l(lock); 47 struct timespec ts; 48 ts.tv_sec = 0; 49 ts.tv_nsec = 1; 50 pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(), 51 &ts); 52 } 53 #endif 54 55 int rv = pthread_cond_destroy(&condition_); 56 DCHECK_EQ(0, rv); 57 } 58 59 void ConditionVariable::Wait() { 60 int rv = pthread_cond_wait(&condition_, user_mutex_); 61 DCHECK_EQ(0, rv); 62 } 63 64 void ConditionVariable::TimedWait(const base::TimeDelta& max_time) { 65 int64_t usecs = max_time.InMicroseconds(); 66 struct timespec relative_time; 67 relative_time.tv_sec = usecs / base::Time::kMicrosecondsPerSecond; 68 relative_time.tv_nsec = (usecs % base::Time::kMicrosecondsPerSecond) * 69 base::Time::kNanosecondsPerMicrosecond; 70 71 #if defined(XP_DARWIN) 72 int rv = pthread_cond_timedwait_relative_np(&condition_, user_mutex_, 73 &relative_time); 74 #else 75 // The timeout argument to pthread_cond_timedwait is in absolute time. 76 struct timespec absolute_time; 77 struct timespec now; 78 clock_gettime(CLOCK_MONOTONIC, &now); 79 absolute_time.tv_sec = now.tv_sec; 80 absolute_time.tv_nsec = now.tv_nsec; 81 82 absolute_time.tv_sec += relative_time.tv_sec; 83 absolute_time.tv_nsec += relative_time.tv_nsec; 84 absolute_time.tv_sec += 85 absolute_time.tv_nsec / base::Time::kNanosecondsPerSecond; 86 absolute_time.tv_nsec %= base::Time::kNanosecondsPerSecond; 87 DCHECK_GE(absolute_time.tv_sec, now.tv_sec); // Overflow paranoia 88 89 # if defined(ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) 90 int rv = pthread_cond_timedwait_monotonic_np(&condition_, user_mutex_, 91 &absolute_time); 92 # else 93 int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time); 94 # endif // ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC 95 #endif // XP_DARWIN 96 97 // On failure, we only expect the CV to timeout. Any other error value means 98 // that we've unexpectedly woken up. 99 DCHECK(rv == 0 || rv == ETIMEDOUT); 100 } 101 102 void ConditionVariable::Broadcast() { 103 int rv = pthread_cond_broadcast(&condition_); 104 DCHECK_EQ(0, rv); 105 } 106 107 void ConditionVariable::Signal() { 108 int rv = pthread_cond_signal(&condition_); 109 DCHECK_EQ(0, rv); 110 }