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);
79 bool first_pass =
true;
82 int32_t x = futex_.load(std::memory_order_relaxed);
84 if (!futex_.compare_exchange_weak(
x,
x - 1,
85 std::memory_order_acquire,
86 std::memory_order_relaxed)) {
95 if (
err == -EINTR ||
err == -EWOULDBLOCK) {
97 }
else if (
err == -ETIMEDOUT) {
108 if (futex_.fetch_add(1, std::memory_order_release) == 0) {
116 const int err = Futex::Wake(&futex_, 1);
122 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
124 class PthreadMutexHolder {
126 explicit PthreadMutexHolder(pthread_mutex_t *
mu) :
mu_(
mu) {
127 const int err = pthread_mutex_lock(
mu_);
133 PthreadMutexHolder(
const PthreadMutexHolder &rhs) =
delete;
134 PthreadMutexHolder &operator=(
const PthreadMutexHolder &rhs) =
delete;
136 ~PthreadMutexHolder() {
137 const int err = pthread_mutex_unlock(
mu_);
144 pthread_mutex_t *
mu_;
148 const int err = pthread_mutex_init(&
mu_, 0);
153 const int err2 = pthread_cond_init(&
cv_, 0);
163 struct timespec abs_timeout;
164 if (
t.has_timeout()) {
165 abs_timeout =
t.MakeAbsTimespec();
168 PthreadMutexHolder
h(&
mu_);
173 bool first_pass =
true;
174 while (wakeup_count_ == 0) {
177 if (!
t.has_timeout()) {
178 const int err = pthread_cond_wait(&
cv_, &
mu_);
183 const int err = pthread_cond_timedwait(&
cv_, &
mu_, &abs_timeout);
184 if (
err == ETIMEDOUT) {
201 PthreadMutexHolder
h(&
mu_);
203 InternalCondVarPoke();
207 PthreadMutexHolder
h(&
mu_);
208 InternalCondVarPoke();
211 void Waiter::InternalCondVarPoke() {
212 if (waiter_count_ != 0) {
213 const int err = pthread_cond_signal(&
cv_);
220 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
226 wakeups_.store(0, std::memory_order_relaxed);
230 struct timespec abs_timeout;
231 if (
t.has_timeout()) {
232 abs_timeout =
t.MakeAbsTimespec();
238 bool first_pass =
true;
240 int x =
wakeups_.load(std::memory_order_relaxed);
243 std::memory_order_acquire,
244 std::memory_order_relaxed)) {
254 if (!
t.has_timeout()) {
256 if (errno == EINTR)
continue;
259 if (sem_timedwait(&sem_, &abs_timeout) == 0)
break;
260 if (errno == EINTR)
continue;
261 if (errno == ETIMEDOUT)
return false;
271 if (
wakeups_.fetch_add(1, std::memory_order_release) == 0) {
283 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
285 class Waiter::WinHelper {
288 return reinterpret_cast<SRWLOCK *
>(&w->mu_storage_);
295 static_assert(
sizeof(
SRWLOCK) ==
sizeof(
void *),
296 "`mu_storage_` does not have the same size as SRWLOCK");
297 static_assert(
alignof(
SRWLOCK) ==
alignof(
void *),
298 "`mu_storage_` does not have the same alignment as SRWLOCK");
301 "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size "
302 "as `CONDITION_VARIABLE`");
305 "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`");
310 "The `SRWLOCK` type must be trivially constructible");
313 "The `CONDITION_VARIABLE` type must be trivially constructible");
315 "The `SRWLOCK` type must be trivially destructible");
317 "The `CONDITION_VARIABLE` type must be trivially destructible");
323 AcquireSRWLockExclusive(
mu_);
326 LockHolder(
const LockHolder&) =
delete;
327 LockHolder& operator=(
const LockHolder&) =
delete;
330 ReleaseSRWLockExclusive(
mu_);
340 InitializeSRWLock(
mu);
341 InitializeConditionVariable(
cv);
356 bool first_pass =
true;
357 while (wakeup_count_ == 0) {
360 if (!SleepConditionVariableSRW(
cv,
mu,
t.InMillisecondsFromNow(), 0)) {
364 const unsigned long err{GetLastError()};
365 if (
err == ERROR_TIMEOUT) {
381 LockHolder
h(WinHelper::GetLock(
this));
383 InternalCondVarPoke();
387 LockHolder
h(WinHelper::GetLock(
this));
388 InternalCondVarPoke();
391 void Waiter::InternalCondVarPoke() {
392 if (waiter_count_ != 0) {
393 WakeConditionVariable(WinHelper::GetCond(
this));
398 #error Unknown ABSL_WAITER_MODE