| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/synchronization/internal/futex_waiter.h" |
|
|
| #ifdef ABSL_INTERNAL_HAVE_FUTEX_WAITER |
|
|
| #include <atomic> |
| #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" |
| #include "absl/synchronization/internal/futex.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace synchronization_internal { |
|
|
| #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL |
| constexpr char FutexWaiter::kName[]; |
| #endif |
|
|
| int FutexWaiter::WaitUntil(std::atomic<int32_t>* v, int32_t val, |
| KernelTimeout t) { |
| #ifdef CLOCK_MONOTONIC |
| constexpr bool kHasClockMonotonic = true; |
| #else |
| constexpr bool kHasClockMonotonic = false; |
| #endif |
|
|
| |
| |
| if (!t.has_timeout()) { |
| return Futex::Wait(v, val); |
| } else if (kHasClockMonotonic && KernelTimeout::SupportsSteadyClock() && |
| t.is_relative_timeout()) { |
| auto rel_timespec = t.MakeRelativeTimespec(); |
| return Futex::WaitRelativeTimeout(v, val, &rel_timespec); |
| } else { |
| auto abs_timespec = t.MakeAbsTimespec(); |
| return Futex::WaitAbsoluteTimeout(v, val, &abs_timespec); |
| } |
| } |
|
|
| bool FutexWaiter::Wait(KernelTimeout t) { |
| |
| |
| |
| |
| bool first_pass = true; |
| while (true) { |
| int32_t x = futex_.load(std::memory_order_relaxed); |
| while (x != 0) { |
| if (!futex_.compare_exchange_weak(x, x - 1, |
| std::memory_order_acquire, |
| std::memory_order_relaxed)) { |
| continue; |
| } |
| return true; |
| } |
|
|
| if (!first_pass) MaybeBecomeIdle(); |
| const int err = WaitUntil(&futex_, 0, t); |
| if (err != 0) { |
| if (err == -EINTR || err == -EWOULDBLOCK) { |
| |
| } else if (err == -ETIMEDOUT) { |
| return false; |
| } else { |
| ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err); |
| } |
| } |
| first_pass = false; |
| } |
| } |
|
|
| void FutexWaiter::Post() { |
| if (futex_.fetch_add(1, std::memory_order_release) == 0) { |
| |
| Poke(); |
| } |
| } |
|
|
| void FutexWaiter::Poke() { |
| |
| const int err = Futex::Wake(&futex_, 1); |
| if (ABSL_PREDICT_FALSE(err < 0)) { |
| ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err); |
| } |
| } |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|