15 #include "absl/synchronization/internal/waiter.h"
17 #include "absl/base/config.h"
28 #include <linux/futex.h>
29 #include <sys/syscall.h>
32 #ifdef ABSL_HAVE_SEMAPHORE_H
33 #include <semaphore.h>
44 #include <type_traits>
46 #include "absl/base/internal/raw_logging.h"
47 #include "absl/base/internal/thread_identity.h"
48 #include "absl/base/optimization.h"
49 #include "absl/synchronization/internal/kernel_timeout.h"
54 namespace synchronization_internal {
59 assert(identity !=
nullptr);
60 const bool is_idle = identity->
is_idle.load(std::memory_order_relaxed);
61 const int ticker = identity->
ticker.load(std::memory_order_relaxed);
62 const int wait_start = identity->
wait_start.load(std::memory_order_relaxed);
64 identity->
is_idle.store(
true, std::memory_order_relaxed);
68 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
71 futex_.store(0, std::memory_order_relaxed);
81 bool first_pass =
true;
84 int32_t x = futex_.load(std::memory_order_relaxed);
86 if (!futex_.compare_exchange_weak(x, x - 1,
87 std::memory_order_acquire,
88 std::memory_order_relaxed)) {
97 if (
err == -EINTR ||
err == -EWOULDBLOCK) {
99 }
else if (
err == -ETIMEDOUT) {
110 if (futex_.fetch_add(1, std::memory_order_release) == 0) {
118 const int err = Futex::Wake(&futex_, 1);
124 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
126 class PthreadMutexHolder {
128 explicit PthreadMutexHolder(pthread_mutex_t *
mu) :
mu_(
mu) {
129 const int err = pthread_mutex_lock(
mu_);
135 PthreadMutexHolder(
const PthreadMutexHolder &rhs) =
delete;
136 PthreadMutexHolder &operator=(
const PthreadMutexHolder &rhs) =
delete;
138 ~PthreadMutexHolder() {
139 const int err = pthread_mutex_unlock(
mu_);
146 pthread_mutex_t *
mu_;
150 const int err = pthread_mutex_init(&
mu_, 0);
155 const int err2 = pthread_cond_init(&
cv_, 0);
165 const int err = pthread_mutex_destroy(&
mu_);
170 const int err2 = pthread_cond_destroy(&
cv_);
177 struct timespec abs_timeout;
178 if (
t.has_timeout()) {
179 abs_timeout =
t.MakeAbsTimespec();
182 PthreadMutexHolder
h(&
mu_);
187 bool first_pass =
true;
188 while (wakeup_count_ == 0) {
191 if (!
t.has_timeout()) {
192 const int err = pthread_cond_wait(&
cv_, &
mu_);
197 const int err = pthread_cond_timedwait(&
cv_, &
mu_, &abs_timeout);
198 if (
err == ETIMEDOUT) {
215 PthreadMutexHolder
h(&
mu_);
217 InternalCondVarPoke();
221 PthreadMutexHolder
h(&
mu_);
222 InternalCondVarPoke();
225 void Waiter::InternalCondVarPoke() {
226 if (waiter_count_ != 0) {
227 const int err = pthread_cond_signal(&
cv_);
234 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
240 wakeups_.store(0, std::memory_order_relaxed);
250 struct timespec abs_timeout;
251 if (
t.has_timeout()) {
252 abs_timeout =
t.MakeAbsTimespec();
258 bool first_pass =
true;
260 int x =
wakeups_.load(std::memory_order_relaxed);
263 std::memory_order_acquire,
264 std::memory_order_relaxed)) {
274 if (!
t.has_timeout()) {
276 if (errno == EINTR)
continue;
279 if (sem_timedwait(&sem_, &abs_timeout) == 0)
break;
280 if (errno == EINTR)
continue;
281 if (errno == ETIMEDOUT)
return false;
291 if (
wakeups_.fetch_add(1, std::memory_order_release) == 0) {
303 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
305 class Waiter::WinHelper {
308 return reinterpret_cast<SRWLOCK *
>(&w->mu_storage_);
315 static_assert(
sizeof(
SRWLOCK) ==
sizeof(
void *),
316 "`mu_storage_` does not have the same size as SRWLOCK");
317 static_assert(
alignof(
SRWLOCK) ==
alignof(
void *),
318 "`mu_storage_` does not have the same alignment as SRWLOCK");
321 "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size "
322 "as `CONDITION_VARIABLE`");
325 "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`");
330 "The `SRWLOCK` type must be trivially constructible");
333 "The `CONDITION_VARIABLE` type must be trivially constructible");
335 "The `SRWLOCK` type must be trivially destructible");
337 "The `CONDITION_VARIABLE` type must be trivially destructible");
343 AcquireSRWLockExclusive(
mu_);
346 LockHolder(
const LockHolder&) =
delete;
347 LockHolder& operator=(
const LockHolder&) =
delete;
350 ReleaseSRWLockExclusive(
mu_);
360 InitializeSRWLock(
mu);
361 InitializeConditionVariable(
cv);
381 bool first_pass =
true;
382 while (wakeup_count_ == 0) {
385 if (!SleepConditionVariableSRW(
cv,
mu,
t.InMillisecondsFromNow(), 0)) {
389 const unsigned long err{GetLastError()};
390 if (
err == ERROR_TIMEOUT) {
406 LockHolder
h(WinHelper::GetLock(
this));
408 InternalCondVarPoke();
412 LockHolder
h(WinHelper::GetLock(
this));
413 InternalCondVarPoke();
416 void Waiter::InternalCondVarPoke() {
417 if (waiter_count_ != 0) {
418 WakeConditionVariable(WinHelper::GetCond(
this));
423 #error Unknown ABSL_WAITER_MODE