1*9356374aSAndroid Build Coastguard Worker // Copyright 2023 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/internal/pthread_waiter.h"
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_INTERNAL_HAVE_PTHREAD_WAITER
18*9356374aSAndroid Build Coastguard Worker
19*9356374aSAndroid Build Coastguard Worker #include <pthread.h>
20*9356374aSAndroid Build Coastguard Worker #include <sys/time.h>
21*9356374aSAndroid Build Coastguard Worker #include <unistd.h>
22*9356374aSAndroid Build Coastguard Worker
23*9356374aSAndroid Build Coastguard Worker #include <cassert>
24*9356374aSAndroid Build Coastguard Worker #include <cerrno>
25*9356374aSAndroid Build Coastguard Worker
26*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
27*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/raw_logging.h"
28*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/thread_identity.h"
29*9356374aSAndroid Build Coastguard Worker #include "absl/base/optimization.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/internal/kernel_timeout.h"
31*9356374aSAndroid Build Coastguard Worker
32*9356374aSAndroid Build Coastguard Worker namespace absl {
33*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
34*9356374aSAndroid Build Coastguard Worker namespace synchronization_internal {
35*9356374aSAndroid Build Coastguard Worker
36*9356374aSAndroid Build Coastguard Worker namespace {
37*9356374aSAndroid Build Coastguard Worker class PthreadMutexHolder {
38*9356374aSAndroid Build Coastguard Worker public:
PthreadMutexHolder(pthread_mutex_t * mu)39*9356374aSAndroid Build Coastguard Worker explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
40*9356374aSAndroid Build Coastguard Worker const int err = pthread_mutex_lock(mu_);
41*9356374aSAndroid Build Coastguard Worker if (err != 0) {
42*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
43*9356374aSAndroid Build Coastguard Worker }
44*9356374aSAndroid Build Coastguard Worker }
45*9356374aSAndroid Build Coastguard Worker
46*9356374aSAndroid Build Coastguard Worker PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
47*9356374aSAndroid Build Coastguard Worker PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
48*9356374aSAndroid Build Coastguard Worker
~PthreadMutexHolder()49*9356374aSAndroid Build Coastguard Worker ~PthreadMutexHolder() {
50*9356374aSAndroid Build Coastguard Worker const int err = pthread_mutex_unlock(mu_);
51*9356374aSAndroid Build Coastguard Worker if (err != 0) {
52*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
53*9356374aSAndroid Build Coastguard Worker }
54*9356374aSAndroid Build Coastguard Worker }
55*9356374aSAndroid Build Coastguard Worker
56*9356374aSAndroid Build Coastguard Worker private:
57*9356374aSAndroid Build Coastguard Worker pthread_mutex_t *mu_;
58*9356374aSAndroid Build Coastguard Worker };
59*9356374aSAndroid Build Coastguard Worker } // namespace
60*9356374aSAndroid Build Coastguard Worker
61*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
62*9356374aSAndroid Build Coastguard Worker constexpr char PthreadWaiter::kName[];
63*9356374aSAndroid Build Coastguard Worker #endif
64*9356374aSAndroid Build Coastguard Worker
PthreadWaiter()65*9356374aSAndroid Build Coastguard Worker PthreadWaiter::PthreadWaiter() : waiter_count_(0), wakeup_count_(0) {
66*9356374aSAndroid Build Coastguard Worker const int err = pthread_mutex_init(&mu_, 0);
67*9356374aSAndroid Build Coastguard Worker if (err != 0) {
68*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
69*9356374aSAndroid Build Coastguard Worker }
70*9356374aSAndroid Build Coastguard Worker
71*9356374aSAndroid Build Coastguard Worker const int err2 = pthread_cond_init(&cv_, 0);
72*9356374aSAndroid Build Coastguard Worker if (err2 != 0) {
73*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
74*9356374aSAndroid Build Coastguard Worker }
75*9356374aSAndroid Build Coastguard Worker }
76*9356374aSAndroid Build Coastguard Worker
77*9356374aSAndroid Build Coastguard Worker #ifdef __APPLE__
78*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1
79*9356374aSAndroid Build Coastguard Worker #endif
80*9356374aSAndroid Build Coastguard Worker
81*9356374aSAndroid Build Coastguard Worker #if defined(__GLIBC__) && \
82*9356374aSAndroid Build Coastguard Worker (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30))
83*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_HAVE_PTHREAD_COND_CLOCKWAIT 1
84*9356374aSAndroid Build Coastguard Worker #elif defined(__ANDROID_API__) && __ANDROID_API__ >= 30
85*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_HAVE_PTHREAD_COND_CLOCKWAIT 1
86*9356374aSAndroid Build Coastguard Worker #endif
87*9356374aSAndroid Build Coastguard Worker
88*9356374aSAndroid Build Coastguard Worker // Calls pthread_cond_timedwait() or possibly something else like
89*9356374aSAndroid Build Coastguard Worker // pthread_cond_timedwait_relative_np() depending on the platform and
90*9356374aSAndroid Build Coastguard Worker // KernelTimeout requested. The return value is the same as the return
91*9356374aSAndroid Build Coastguard Worker // value of pthread_cond_timedwait().
TimedWait(KernelTimeout t)92*9356374aSAndroid Build Coastguard Worker int PthreadWaiter::TimedWait(KernelTimeout t) {
93*9356374aSAndroid Build Coastguard Worker assert(t.has_timeout());
94*9356374aSAndroid Build Coastguard Worker if (KernelTimeout::SupportsSteadyClock() && t.is_relative_timeout()) {
95*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_INTERNAL_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
96*9356374aSAndroid Build Coastguard Worker const auto rel_timeout = t.MakeRelativeTimespec();
97*9356374aSAndroid Build Coastguard Worker return pthread_cond_timedwait_relative_np(&cv_, &mu_, &rel_timeout);
98*9356374aSAndroid Build Coastguard Worker #elif defined(ABSL_INTERNAL_HAVE_PTHREAD_COND_CLOCKWAIT) && \
99*9356374aSAndroid Build Coastguard Worker defined(CLOCK_MONOTONIC)
100*9356374aSAndroid Build Coastguard Worker const auto abs_clock_timeout = t.MakeClockAbsoluteTimespec(CLOCK_MONOTONIC);
101*9356374aSAndroid Build Coastguard Worker return pthread_cond_clockwait(&cv_, &mu_, CLOCK_MONOTONIC,
102*9356374aSAndroid Build Coastguard Worker &abs_clock_timeout);
103*9356374aSAndroid Build Coastguard Worker #endif
104*9356374aSAndroid Build Coastguard Worker }
105*9356374aSAndroid Build Coastguard Worker
106*9356374aSAndroid Build Coastguard Worker const auto abs_timeout = t.MakeAbsTimespec();
107*9356374aSAndroid Build Coastguard Worker return pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
108*9356374aSAndroid Build Coastguard Worker }
109*9356374aSAndroid Build Coastguard Worker
Wait(KernelTimeout t)110*9356374aSAndroid Build Coastguard Worker bool PthreadWaiter::Wait(KernelTimeout t) {
111*9356374aSAndroid Build Coastguard Worker PthreadMutexHolder h(&mu_);
112*9356374aSAndroid Build Coastguard Worker ++waiter_count_;
113*9356374aSAndroid Build Coastguard Worker // Loop until we find a wakeup to consume or timeout.
114*9356374aSAndroid Build Coastguard Worker // Note that, since the thread ticker is just reset, we don't need to check
115*9356374aSAndroid Build Coastguard Worker // whether the thread is idle on the very first pass of the loop.
116*9356374aSAndroid Build Coastguard Worker bool first_pass = true;
117*9356374aSAndroid Build Coastguard Worker while (wakeup_count_ == 0) {
118*9356374aSAndroid Build Coastguard Worker if (!first_pass) MaybeBecomeIdle();
119*9356374aSAndroid Build Coastguard Worker // No wakeups available, time to wait.
120*9356374aSAndroid Build Coastguard Worker if (!t.has_timeout()) {
121*9356374aSAndroid Build Coastguard Worker const int err = pthread_cond_wait(&cv_, &mu_);
122*9356374aSAndroid Build Coastguard Worker if (err != 0) {
123*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
124*9356374aSAndroid Build Coastguard Worker }
125*9356374aSAndroid Build Coastguard Worker } else {
126*9356374aSAndroid Build Coastguard Worker const int err = TimedWait(t);
127*9356374aSAndroid Build Coastguard Worker if (err == ETIMEDOUT) {
128*9356374aSAndroid Build Coastguard Worker --waiter_count_;
129*9356374aSAndroid Build Coastguard Worker return false;
130*9356374aSAndroid Build Coastguard Worker }
131*9356374aSAndroid Build Coastguard Worker if (err != 0) {
132*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "PthreadWaiter::TimedWait() failed: %d", err);
133*9356374aSAndroid Build Coastguard Worker }
134*9356374aSAndroid Build Coastguard Worker }
135*9356374aSAndroid Build Coastguard Worker first_pass = false;
136*9356374aSAndroid Build Coastguard Worker }
137*9356374aSAndroid Build Coastguard Worker // Consume a wakeup and we're done.
138*9356374aSAndroid Build Coastguard Worker --wakeup_count_;
139*9356374aSAndroid Build Coastguard Worker --waiter_count_;
140*9356374aSAndroid Build Coastguard Worker return true;
141*9356374aSAndroid Build Coastguard Worker }
142*9356374aSAndroid Build Coastguard Worker
Post()143*9356374aSAndroid Build Coastguard Worker void PthreadWaiter::Post() {
144*9356374aSAndroid Build Coastguard Worker PthreadMutexHolder h(&mu_);
145*9356374aSAndroid Build Coastguard Worker ++wakeup_count_;
146*9356374aSAndroid Build Coastguard Worker InternalCondVarPoke();
147*9356374aSAndroid Build Coastguard Worker }
148*9356374aSAndroid Build Coastguard Worker
Poke()149*9356374aSAndroid Build Coastguard Worker void PthreadWaiter::Poke() {
150*9356374aSAndroid Build Coastguard Worker PthreadMutexHolder h(&mu_);
151*9356374aSAndroid Build Coastguard Worker InternalCondVarPoke();
152*9356374aSAndroid Build Coastguard Worker }
153*9356374aSAndroid Build Coastguard Worker
InternalCondVarPoke()154*9356374aSAndroid Build Coastguard Worker void PthreadWaiter::InternalCondVarPoke() {
155*9356374aSAndroid Build Coastguard Worker if (waiter_count_ != 0) {
156*9356374aSAndroid Build Coastguard Worker const int err = pthread_cond_signal(&cv_);
157*9356374aSAndroid Build Coastguard Worker if (ABSL_PREDICT_FALSE(err != 0)) {
158*9356374aSAndroid Build Coastguard Worker ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
159*9356374aSAndroid Build Coastguard Worker }
160*9356374aSAndroid Build Coastguard Worker }
161*9356374aSAndroid Build Coastguard Worker }
162*9356374aSAndroid Build Coastguard Worker
163*9356374aSAndroid Build Coastguard Worker } // namespace synchronization_internal
164*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
165*9356374aSAndroid Build Coastguard Worker } // namespace absl
166*9356374aSAndroid Build Coastguard Worker
167*9356374aSAndroid Build Coastguard Worker #endif // ABSL_INTERNAL_HAVE_PTHREAD_WAITER
168