| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/synchronization/internal/sem_waiter.h" |
|
|
| #ifdef ABSL_INTERNAL_HAVE_SEM_WAITER |
|
|
| #include <semaphore.h> |
|
|
| #include <atomic> |
| #include <cassert> |
| #include <cstdint> |
| #include <cerrno> |
|
|
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/internal/thread_identity.h" |
| #include "absl/base/optimization.h" |
| #include "absl/synchronization/internal/kernel_timeout.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace synchronization_internal { |
|
|
| #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL |
| constexpr char SemWaiter::kName[]; |
| #endif |
|
|
| SemWaiter::SemWaiter() : wakeups_(0) { |
| if (sem_init(&sem_, 0, 0) != 0) { |
| ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno); |
| } |
| } |
|
|
| #if defined(__GLIBC__) && \ |
| (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30)) |
| #define ABSL_INTERNAL_HAVE_SEM_CLOCKWAIT 1 |
| #elif defined(__ANDROID_API__) && __ANDROID_API__ >= 30 |
| #define ABSL_INTERNAL_HAVE_SEM_CLOCKWAIT 1 |
| #endif |
|
|
| |
| |
| |
| |
| int SemWaiter::TimedWait(KernelTimeout t) { |
| if (KernelTimeout::SupportsSteadyClock() && t.is_relative_timeout()) { |
| #if defined(ABSL_INTERNAL_HAVE_SEM_CLOCKWAIT) && defined(CLOCK_MONOTONIC) |
| const auto abs_clock_timeout = t.MakeClockAbsoluteTimespec(CLOCK_MONOTONIC); |
| return sem_clockwait(&sem_, CLOCK_MONOTONIC, &abs_clock_timeout); |
| #endif |
| } |
|
|
| const auto abs_timeout = t.MakeAbsTimespec(); |
| return sem_timedwait(&sem_, &abs_timeout); |
| } |
|
|
| bool SemWaiter::Wait(KernelTimeout t) { |
| |
| |
| |
| bool first_pass = true; |
| while (true) { |
| int x = wakeups_.load(std::memory_order_relaxed); |
| while (x != 0) { |
| if (!wakeups_.compare_exchange_weak(x, x - 1, |
| std::memory_order_acquire, |
| std::memory_order_relaxed)) { |
| continue; |
| } |
| |
| return true; |
| } |
|
|
| if (!first_pass) MaybeBecomeIdle(); |
| |
| while (true) { |
| if (!t.has_timeout()) { |
| if (sem_wait(&sem_) == 0) break; |
| if (errno == EINTR) continue; |
| ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno); |
| } else { |
| if (TimedWait(t) == 0) break; |
| if (errno == EINTR) continue; |
| if (errno == ETIMEDOUT) return false; |
| ABSL_RAW_LOG(FATAL, "SemWaiter::TimedWait() failed: %d", errno); |
| } |
| } |
| first_pass = false; |
| } |
| } |
|
|
| void SemWaiter::Post() { |
| |
| if (wakeups_.fetch_add(1, std::memory_order_release) == 0) { |
| |
| Poke(); |
| } |
| } |
|
|
| void SemWaiter::Poke() { |
| if (sem_post(&sem_) != 0) { |
| ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno); |
| } |
| } |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|