28 #include <linux/futex.h> 29 #include <sys/syscall.h> 32 #ifdef ABSL_HAVE_SEMAPHORE_H 33 #include <semaphore.h> 44 #include <type_traits> 52 namespace synchronization_internal {
57 assert(identity !=
nullptr);
58 const bool is_idle = identity->
is_idle.load(std::memory_order_relaxed);
59 const int ticker = identity->
ticker.load(std::memory_order_relaxed);
60 const int wait_start = identity->
wait_start.load(std::memory_order_relaxed);
62 identity->
is_idle.store(
true, std::memory_order_relaxed);
66 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX 72 #define SYS_futex __NR_futex 74 #ifndef FUTEX_WAIT_BITSET 75 #define FUTEX_WAIT_BITSET 9 77 #ifndef FUTEX_PRIVATE_FLAG 78 #define FUTEX_PRIVATE_FLAG 128 80 #ifndef FUTEX_CLOCK_REALTIME 81 #define FUTEX_CLOCK_REALTIME 256 83 #ifndef FUTEX_BITSET_MATCH_ANY 84 #define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF 90 static int WaitUntil(std::atomic<int32_t> *
v, int32_t val,
100 SYS_futex, reinterpret_cast<int32_t *>(v),
101 FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
102 &abs_timeout,
nullptr, FUTEX_BITSET_MATCH_ANY);
106 err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
107 FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val,
nullptr);
115 static int Wake(std::atomic<int32_t> *
v, int32_t count) {
116 int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
117 FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
126 futex_.store(0, std::memory_order_relaxed);
133 int32_t x = futex_.load(std::memory_order_relaxed);
135 if (!futex_.compare_exchange_weak(x, x - 1,
136 std::memory_order_acquire,
137 std::memory_order_relaxed)) {
145 if (err == -EINTR || err == -EWOULDBLOCK) {
147 }
else if (err == -ETIMEDOUT) {
150 ABSL_RAW_LOG(FATAL,
"Futex operation failed with error %d\n", err);
159 if (futex_.fetch_add(1, std::memory_order_release) == 0) {
169 ABSL_RAW_LOG(FATAL,
"Futex operation failed with error %d\n", err);
173 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR 175 class PthreadMutexHolder {
177 explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
178 const int err = pthread_mutex_lock(mu_);
180 ABSL_RAW_LOG(FATAL,
"pthread_mutex_lock failed: %d", err);
184 PthreadMutexHolder(
const PthreadMutexHolder &rhs) =
delete;
185 PthreadMutexHolder &operator=(
const PthreadMutexHolder &rhs) =
delete;
187 ~PthreadMutexHolder() {
188 const int err = pthread_mutex_unlock(mu_);
190 ABSL_RAW_LOG(FATAL,
"pthread_mutex_unlock failed: %d", err);
195 pthread_mutex_t *mu_;
199 const int err = pthread_mutex_init(&mu_, 0);
201 ABSL_RAW_LOG(FATAL,
"pthread_mutex_init failed: %d", err);
204 const int err2 = pthread_cond_init(&cv_, 0);
206 ABSL_RAW_LOG(FATAL,
"pthread_cond_init failed: %d", err2);
209 waiter_count_.store(0, std::memory_order_relaxed);
210 wakeup_count_.store(0, std::memory_order_relaxed);
214 struct timespec abs_timeout;
219 PthreadMutexHolder h(&mu_);
220 waiter_count_.fetch_add(1, std::memory_order_relaxed);
223 int x = wakeup_count_.load(std::memory_order_relaxed);
225 if (!wakeup_count_.compare_exchange_weak(x, x - 1,
226 std::memory_order_acquire,
227 std::memory_order_relaxed)) {
231 waiter_count_.fetch_sub(1, std::memory_order_relaxed);
237 const int err = pthread_cond_wait(&cv_, &mu_);
239 ABSL_RAW_LOG(FATAL,
"pthread_cond_wait failed: %d", err);
242 const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
243 if (err == ETIMEDOUT) {
244 waiter_count_.fetch_sub(1, std::memory_order_relaxed);
248 ABSL_RAW_LOG(FATAL,
"pthread_cond_wait failed: %d", err);
256 wakeup_count_.fetch_add(1, std::memory_order_release);
261 if (waiter_count_.load(std::memory_order_relaxed) == 0) {
265 PthreadMutexHolder h(&mu_);
266 if (waiter_count_.load(std::memory_order_relaxed) == 0) {
269 const int err = pthread_cond_signal(&cv_);
271 ABSL_RAW_LOG(FATAL,
"pthread_cond_signal failed: %d", err);
275 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM 278 if (sem_init(&sem_, 0, 0) != 0) {
279 ABSL_RAW_LOG(FATAL,
"sem_init failed with errno %d\n", errno);
281 wakeups_.store(0, std::memory_order_relaxed);
285 struct timespec abs_timeout;
292 int x = wakeups_.load(std::memory_order_relaxed);
294 if (!wakeups_.compare_exchange_weak(x, x - 1,
295 std::memory_order_acquire,
296 std::memory_order_relaxed)) {
306 if (sem_wait(&sem_) == 0)
break;
307 if (errno == EINTR)
continue;
310 if (sem_timedwait(&sem_, &abs_timeout) == 0)
break;
311 if (errno == EINTR)
continue;
312 if (errno == ETIMEDOUT)
return false;
321 wakeups_.fetch_add(1, std::memory_order_release);
326 if (sem_post(&sem_) != 0) {
327 ABSL_RAW_LOG(FATAL,
"sem_post failed with errno %d\n", errno);
331 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 333 class Waiter::WinHelper {
335 static SRWLOCK *GetLock(
Waiter *w) {
336 return reinterpret_cast<SRWLOCK *
>(&w->mu_storage_);
339 static CONDITION_VARIABLE *GetCond(
Waiter *w) {
340 return reinterpret_cast<CONDITION_VARIABLE *
>(&w->cv_storage_);
343 static_assert(
sizeof(SRWLOCK) ==
sizeof(Waiter::SRWLockStorage),
344 "SRWLockStorage does not have the same size as SRWLOCK");
346 alignof(SRWLOCK) ==
alignof(Waiter::SRWLockStorage),
347 "SRWLockStorage does not have the same alignment as SRWLOCK");
349 static_assert(
sizeof(CONDITION_VARIABLE) ==
350 sizeof(Waiter::ConditionVariableStorage),
351 "ABSL_CONDITION_VARIABLE_STORAGE does not have the same size " 352 "as CONDITION_VARIABLE");
353 static_assert(
alignof(CONDITION_VARIABLE) ==
354 alignof(Waiter::ConditionVariableStorage),
355 "ConditionVariableStorage does not have the same " 356 "alignment as CONDITION_VARIABLE");
361 "The SRWLOCK type must be trivially constructible");
363 "The CONDITION_VARIABLE type must be trivially constructible");
365 "The SRWLOCK type must be trivially destructible");
367 "The CONDITION_VARIABLE type must be trivially destructible");
372 explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
373 AcquireSRWLockExclusive(mu_);
376 LockHolder(
const LockHolder&) =
delete;
377 LockHolder& operator=(
const LockHolder&) =
delete;
380 ReleaseSRWLockExclusive(mu_);
388 auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK;
389 auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE;
390 InitializeSRWLock(mu);
391 InitializeConditionVariable(cv);
392 waiter_count_.store(0, std::memory_order_relaxed);
393 wakeup_count_.store(0, std::memory_order_relaxed);
397 SRWLOCK *mu = WinHelper::GetLock(
this);
398 CONDITION_VARIABLE *cv = WinHelper::GetCond(
this);
401 waiter_count_.fetch_add(1, std::memory_order_relaxed);
405 int x = wakeup_count_.load(std::memory_order_relaxed);
407 if (!wakeup_count_.compare_exchange_weak(x, x - 1,
408 std::memory_order_acquire,
409 std::memory_order_relaxed)) {
413 waiter_count_.fetch_sub(1, std::memory_order_relaxed);
418 if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
422 const unsigned long err{GetLastError()};
423 if (err == ERROR_TIMEOUT) {
424 waiter_count_.fetch_sub(1, std::memory_order_relaxed);
427 ABSL_RAW_LOG(FATAL,
"SleepConditionVariableSRW failed: %lu", err);
436 wakeup_count_.fetch_add(1, std::memory_order_release);
441 if (waiter_count_.load(std::memory_order_relaxed) == 0) {
445 LockHolder h(WinHelper::GetLock(
this));
446 if (waiter_count_.load(std::memory_order_relaxed) == 0) {
449 WakeConditionVariable(WinHelper::GetCond(
this));
453 #error Unknown ABSL_WAITER_MODE
bool Wait(KernelTimeout t)
static int WaitUntil(std::atomic< int32_t > *v, int32_t val, KernelTimeout t)
#define ABSL_RAW_LOG(severity,...)
#define ABSL_PREDICT_FALSE(x)
ThreadIdentity * CurrentThreadIdentityIfPresent()
std::atomic< bool > is_idle
static const int kIdlePeriods
struct timespec MakeAbsTimespec()
static int Wake(std::atomic< int32_t > *v, int32_t count)
std::atomic< int > wait_start
static void MaybeBecomeIdle()
std::atomic< int > ticker