1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/condition_variable.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <errno.h>
8*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
9*6777b538SAndroid Build Coastguard Worker #include <sys/time.h>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include <optional>
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
17*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
20*6777b538SAndroid Build Coastguard Worker #include <atomic>
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
23*6777b538SAndroid Build Coastguard Worker #endif
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID) && __ANDROID_API__ < 21
26*6777b538SAndroid Build Coastguard Worker #define HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC 1
27*6777b538SAndroid Build Coastguard Worker #endif
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker namespace {
30*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
31*6777b538SAndroid Build Coastguard Worker // Under this feature a hack that was introduced to avoid crashes is skipped.
32*6777b538SAndroid Build Coastguard Worker // Use to evaluate if the hack is still needed. See https://crbug.com/517681.
33*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kSkipConditionVariableWakeupHack,
34*6777b538SAndroid Build Coastguard Worker "SkipConditionVariableWakeupHack",
35*6777b538SAndroid Build Coastguard Worker base::FEATURE_ENABLED_BY_DEFAULT);
36*6777b538SAndroid Build Coastguard Worker std::atomic_bool g_skip_wakeup_hack = true;
37*6777b538SAndroid Build Coastguard Worker #endif
38*6777b538SAndroid Build Coastguard Worker } // namespace
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker namespace base {
41*6777b538SAndroid Build Coastguard Worker
ConditionVariable(Lock * user_lock)42*6777b538SAndroid Build Coastguard Worker ConditionVariable::ConditionVariable(Lock* user_lock)
43*6777b538SAndroid Build Coastguard Worker : user_mutex_(user_lock->lock_.native_handle())
44*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
45*6777b538SAndroid Build Coastguard Worker , user_lock_(user_lock)
46*6777b538SAndroid Build Coastguard Worker #endif
47*6777b538SAndroid Build Coastguard Worker {
48*6777b538SAndroid Build Coastguard Worker int rv = 0;
49*6777b538SAndroid Build Coastguard Worker // http://crbug.com/293736
50*6777b538SAndroid Build Coastguard Worker // NaCl doesn't support monotonic clock based absolute deadlines.
51*6777b538SAndroid Build Coastguard Worker // On older Android platform versions, it's supported through the
52*6777b538SAndroid Build Coastguard Worker // non-standard pthread_cond_timedwait_monotonic_np. Newer platform
53*6777b538SAndroid Build Coastguard Worker // versions have pthread_condattr_setclock.
54*6777b538SAndroid Build Coastguard Worker // Mac can use relative time deadlines.
55*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_NACL) && \
56*6777b538SAndroid Build Coastguard Worker !defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
57*6777b538SAndroid Build Coastguard Worker pthread_condattr_t attrs;
58*6777b538SAndroid Build Coastguard Worker rv = pthread_condattr_init(&attrs);
59*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, rv);
60*6777b538SAndroid Build Coastguard Worker pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
61*6777b538SAndroid Build Coastguard Worker rv = pthread_cond_init(&condition_, &attrs);
62*6777b538SAndroid Build Coastguard Worker pthread_condattr_destroy(&attrs);
63*6777b538SAndroid Build Coastguard Worker #else
64*6777b538SAndroid Build Coastguard Worker rv = pthread_cond_init(&condition_, NULL);
65*6777b538SAndroid Build Coastguard Worker #endif
66*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, rv);
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker
~ConditionVariable()69*6777b538SAndroid Build Coastguard Worker ConditionVariable::~ConditionVariable() {
70*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
71*6777b538SAndroid Build Coastguard Worker // This hack is necessary to avoid a fatal pthreads subsystem bug in the
72*6777b538SAndroid Build Coastguard Worker // Darwin kernel. http://crbug.com/517681.
73*6777b538SAndroid Build Coastguard Worker if (!g_skip_wakeup_hack.load(std::memory_order_relaxed)) {
74*6777b538SAndroid Build Coastguard Worker base::Lock lock;
75*6777b538SAndroid Build Coastguard Worker base::AutoLock l(lock);
76*6777b538SAndroid Build Coastguard Worker struct timespec ts;
77*6777b538SAndroid Build Coastguard Worker ts.tv_sec = 0;
78*6777b538SAndroid Build Coastguard Worker ts.tv_nsec = 1;
79*6777b538SAndroid Build Coastguard Worker pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
80*6777b538SAndroid Build Coastguard Worker &ts);
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker #endif
83*6777b538SAndroid Build Coastguard Worker
84*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_destroy(&condition_);
85*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, rv);
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
89*6777b538SAndroid Build Coastguard Worker // static
InitializeFeatures()90*6777b538SAndroid Build Coastguard Worker void ConditionVariable::InitializeFeatures() {
91*6777b538SAndroid Build Coastguard Worker g_skip_wakeup_hack.store(
92*6777b538SAndroid Build Coastguard Worker base::FeatureList::IsEnabled(kSkipConditionVariableWakeupHack),
93*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
94*6777b538SAndroid Build Coastguard Worker }
95*6777b538SAndroid Build Coastguard Worker #endif
96*6777b538SAndroid Build Coastguard Worker
Wait()97*6777b538SAndroid Build Coastguard Worker void ConditionVariable::Wait() {
98*6777b538SAndroid Build Coastguard Worker std::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
99*6777b538SAndroid Build Coastguard Worker scoped_blocking_call;
100*6777b538SAndroid Build Coastguard Worker if (waiting_is_blocking_)
101*6777b538SAndroid Build Coastguard Worker scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
104*6777b538SAndroid Build Coastguard Worker user_lock_->CheckHeldAndUnmark();
105*6777b538SAndroid Build Coastguard Worker #endif
106*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_wait(&condition_, user_mutex_);
107*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, rv);
108*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
109*6777b538SAndroid Build Coastguard Worker user_lock_->CheckUnheldAndMark();
110*6777b538SAndroid Build Coastguard Worker #endif
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker
TimedWait(const TimeDelta & max_time)113*6777b538SAndroid Build Coastguard Worker void ConditionVariable::TimedWait(const TimeDelta& max_time) {
114*6777b538SAndroid Build Coastguard Worker std::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
115*6777b538SAndroid Build Coastguard Worker scoped_blocking_call;
116*6777b538SAndroid Build Coastguard Worker if (waiting_is_blocking_)
117*6777b538SAndroid Build Coastguard Worker scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
118*6777b538SAndroid Build Coastguard Worker
119*6777b538SAndroid Build Coastguard Worker int64_t usecs = max_time.InMicroseconds();
120*6777b538SAndroid Build Coastguard Worker struct timespec relative_time;
121*6777b538SAndroid Build Coastguard Worker relative_time.tv_sec =
122*6777b538SAndroid Build Coastguard Worker static_cast<time_t>(usecs / Time::kMicrosecondsPerSecond);
123*6777b538SAndroid Build Coastguard Worker relative_time.tv_nsec =
124*6777b538SAndroid Build Coastguard Worker (usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
127*6777b538SAndroid Build Coastguard Worker user_lock_->CheckHeldAndUnmark();
128*6777b538SAndroid Build Coastguard Worker #endif
129*6777b538SAndroid Build Coastguard Worker
130*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
131*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_timedwait_relative_np(
132*6777b538SAndroid Build Coastguard Worker &condition_, user_mutex_, &relative_time);
133*6777b538SAndroid Build Coastguard Worker #else
134*6777b538SAndroid Build Coastguard Worker // The timeout argument to pthread_cond_timedwait is in absolute time.
135*6777b538SAndroid Build Coastguard Worker struct timespec absolute_time;
136*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_NACL)
137*6777b538SAndroid Build Coastguard Worker // See comment in constructor for why this is different in NaCl.
138*6777b538SAndroid Build Coastguard Worker struct timeval now;
139*6777b538SAndroid Build Coastguard Worker gettimeofday(&now, NULL);
140*6777b538SAndroid Build Coastguard Worker absolute_time.tv_sec = now.tv_sec;
141*6777b538SAndroid Build Coastguard Worker absolute_time.tv_nsec = now.tv_usec * Time::kNanosecondsPerMicrosecond;
142*6777b538SAndroid Build Coastguard Worker #else
143*6777b538SAndroid Build Coastguard Worker struct timespec now;
144*6777b538SAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &now);
145*6777b538SAndroid Build Coastguard Worker absolute_time.tv_sec = now.tv_sec;
146*6777b538SAndroid Build Coastguard Worker absolute_time.tv_nsec = now.tv_nsec;
147*6777b538SAndroid Build Coastguard Worker #endif
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker absolute_time.tv_sec += relative_time.tv_sec;
150*6777b538SAndroid Build Coastguard Worker absolute_time.tv_nsec += relative_time.tv_nsec;
151*6777b538SAndroid Build Coastguard Worker absolute_time.tv_sec += absolute_time.tv_nsec / Time::kNanosecondsPerSecond;
152*6777b538SAndroid Build Coastguard Worker absolute_time.tv_nsec %= Time::kNanosecondsPerSecond;
153*6777b538SAndroid Build Coastguard Worker DCHECK_GE(absolute_time.tv_sec, now.tv_sec); // Overflow paranoia
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
156*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_timedwait_monotonic_np(
157*6777b538SAndroid Build Coastguard Worker &condition_, user_mutex_, &absolute_time);
158*6777b538SAndroid Build Coastguard Worker #else
159*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time);
160*6777b538SAndroid Build Coastguard Worker #endif // HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
161*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE)
162*6777b538SAndroid Build Coastguard Worker
163*6777b538SAndroid Build Coastguard Worker // On failure, we only expect the CV to timeout. Any other error value means
164*6777b538SAndroid Build Coastguard Worker // that we've unexpectedly woken up.
165*6777b538SAndroid Build Coastguard Worker DCHECK(rv == 0 || rv == ETIMEDOUT);
166*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
167*6777b538SAndroid Build Coastguard Worker user_lock_->CheckUnheldAndMark();
168*6777b538SAndroid Build Coastguard Worker #endif
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker
Broadcast()171*6777b538SAndroid Build Coastguard Worker void ConditionVariable::Broadcast() {
172*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_broadcast(&condition_);
173*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, rv);
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker
Signal()176*6777b538SAndroid Build Coastguard Worker void ConditionVariable::Signal() {
177*6777b538SAndroid Build Coastguard Worker int rv = pthread_cond_signal(&condition_);
178*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, rv);
179*6777b538SAndroid Build Coastguard Worker }
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker } // namespace base
182