Line data Source code
1 : // Copyright (c) 2011 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 "base/condition_variable.h"
6 :
7 : #include <errno.h>
8 : #include <stdint.h>
9 : #include <sys/time.h>
10 :
11 : #include "base/lock.h"
12 : #include "base/time.h"
13 : #include "build/build_config.h"
14 :
15 778 : ConditionVariable::ConditionVariable(Lock* user_lock)
16 778 : : user_mutex_(user_lock->lock_.native_handle())
17 : {
18 780 : int rv = 0;
19 : // http://crbug.com/293736
20 : // NaCl doesn't support monotonic clock based absolute deadlines.
21 : // On older Android platform versions, it's supported through the
22 : // non-standard pthread_cond_timedwait_monotonic_np. Newer platform
23 : // versions have pthread_condattr_setclock.
24 : // Mac can use relative time deadlines.
25 : #if !defined(OS_MACOSX) && !defined(OS_NACL) && \
26 : !(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
27 : pthread_condattr_t attrs;
28 780 : rv = pthread_condattr_init(&attrs);
29 778 : DCHECK_EQ(0, rv);
30 778 : pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
31 777 : rv = pthread_cond_init(&condition_, &attrs);
32 777 : pthread_condattr_destroy(&attrs);
33 : #else
34 : rv = pthread_cond_init(&condition_, NULL);
35 : #endif
36 777 : DCHECK_EQ(0, rv);
37 777 : }
38 :
39 1552 : ConditionVariable::~ConditionVariable() {
40 : #if defined(OS_MACOSX)
41 : // This hack is necessary to avoid a fatal pthreads subsystem bug in the
42 : // Darwin kernel. http://crbug.com/517681.
43 : {
44 : Lock lock;
45 : AutoLock l(lock);
46 : struct timespec ts;
47 : ts.tv_sec = 0;
48 : ts.tv_nsec = 1;
49 : pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
50 : &ts);
51 : }
52 : #endif
53 :
54 776 : int rv = pthread_cond_destroy(&condition_);
55 776 : DCHECK_EQ(0, rv);
56 776 : }
57 :
58 254 : void ConditionVariable::Wait() {
59 254 : int rv = pthread_cond_wait(&condition_, user_mutex_);
60 249 : DCHECK_EQ(0, rv);
61 249 : }
62 :
63 527 : void ConditionVariable::TimedWait(const base::TimeDelta& max_time) {
64 527 : int64_t usecs = max_time.InMicroseconds();
65 : struct timespec relative_time;
66 527 : relative_time.tv_sec = usecs / base::Time::kMicrosecondsPerSecond;
67 527 : relative_time.tv_nsec =
68 527 : (usecs % base::Time::kMicrosecondsPerSecond) * base::Time::kNanosecondsPerMicrosecond;
69 :
70 : #if defined(OS_MACOSX)
71 : int rv = pthread_cond_timedwait_relative_np(
72 : &condition_, user_mutex_, &relative_time);
73 : #else
74 : // The timeout argument to pthread_cond_timedwait is in absolute time.
75 : struct timespec absolute_time;
76 : #if defined(OS_NACL)
77 : // See comment in constructor for why this is different in NaCl.
78 : struct timeval now;
79 : gettimeofday(&now, NULL);
80 : absolute_time.tv_sec = now.tv_sec;
81 : absolute_time.tv_nsec = now.tv_usec * base::Time::kNanosecondsPerMicrosecond;
82 : #else
83 : struct timespec now;
84 527 : clock_gettime(CLOCK_MONOTONIC, &now);
85 527 : absolute_time.tv_sec = now.tv_sec;
86 527 : absolute_time.tv_nsec = now.tv_nsec;
87 : #endif
88 :
89 527 : absolute_time.tv_sec += relative_time.tv_sec;
90 527 : absolute_time.tv_nsec += relative_time.tv_nsec;
91 527 : absolute_time.tv_sec += absolute_time.tv_nsec / base::Time::kNanosecondsPerSecond;
92 527 : absolute_time.tv_nsec %= base::Time::kNanosecondsPerSecond;
93 527 : DCHECK_GE(absolute_time.tv_sec, now.tv_sec); // Overflow paranoia
94 :
95 : #if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
96 : int rv = pthread_cond_timedwait_monotonic_np(
97 : &condition_, user_mutex_, &absolute_time);
98 : #else
99 527 : int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time);
100 : #endif // OS_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
101 : #endif // OS_MACOSX
102 :
103 : // On failure, we only expect the CV to timeout. Any other error value means
104 : // that we've unexpectedly woken up.
105 527 : DCHECK(rv == 0 || rv == ETIMEDOUT);
106 527 : }
107 :
108 253 : void ConditionVariable::Broadcast() {
109 253 : int rv = pthread_cond_broadcast(&condition_);
110 253 : DCHECK_EQ(0, rv);
111 253 : }
112 :
113 0 : void ConditionVariable::Signal() {
114 0 : int rv = pthread_cond_signal(&condition_);
115 0 : DCHECK_EQ(0, rv);
116 0 : }
|