aboutsummaryrefslogtreecommitdiff
path: root/absl/synchronization/internal/waiter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/synchronization/internal/waiter.cc')
-rw-r--r--absl/synchronization/internal/waiter.cc106
1 files changed, 5 insertions, 101 deletions
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 4eee1298..f2051d67 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -67,74 +67,11 @@ static void MaybeBecomeIdle() {
#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
-Waiter::Waiter() : futex_(0) {}
-
-bool Waiter::WaitAbsoluteTimeout(KernelTimeout t) {
- // Loop until we can atomically decrement futex from a positive
- // value, waiting on a futex while we believe it is zero.
- // Note that, since the thread ticker is just reset, we don't need to check
- // whether the thread is idle on the very first pass of the loop.
- 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; // Raced with someone, retry.
- }
- return true; // Consumed a wakeup, we are done.
- }
-
- if (!first_pass) MaybeBecomeIdle();
- auto abs_timeout = t.MakeAbsTimespec();
- const int err = Futex::WaitAbsoluteTimeout(&futex_, 0, &abs_timeout);
- if (err != 0) {
- if (err == -EINTR || err == -EWOULDBLOCK) {
- // Do nothing, the loop will retry.
- } else if (err == -ETIMEDOUT) {
- return false;
- } else {
- ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
- }
- }
- first_pass = false;
- }
-}
-
-#ifdef CLOCK_MONOTONIC
-
-// Subtracts the timespec `sub` from `in` if the result would not be negative,
-// and returns true. Returns false if the result would be negative, and leaves
-// `in` unchanged.
-static bool TimespecSubtract(struct timespec& in, const struct timespec& sub) {
- if (in.tv_sec < sub.tv_sec) {
- return false;
- }
- if (in.tv_nsec < sub.tv_nsec) {
- if (in.tv_sec == sub.tv_sec) {
- return false;
- }
- // Borrow from tv_sec.
- in.tv_sec -= 1;
- in.tv_nsec += 1'000'000'000;
- }
- in.tv_sec -= sub.tv_sec;
- in.tv_nsec -= sub.tv_nsec;
- return true;
+Waiter::Waiter() {
+ futex_.store(0, std::memory_order_relaxed);
}
-// On some platforms a background thread periodically calls `Poke()` to briefly
-// wake waiter threads so that they may call `MaybeBecomeIdle()`. This means
-// that `WaitRelativeTimeout()` differs slightly from `WaitAbsoluteTimeout()`
-// because it must adjust the timeout by the amount of time that it has already
-// slept.
-bool Waiter::WaitRelativeTimeout(KernelTimeout t) {
- struct timespec start;
- ABSL_RAW_CHECK(clock_gettime(CLOCK_MONOTONIC, &start) == 0,
- "clock_gettime() failed");
-
+bool Waiter::Wait(KernelTimeout t) {
// Loop until we can atomically decrement futex from a positive
// value, waiting on a futex while we believe it is zero.
// Note that, since the thread ticker is just reset, we don't need to check
@@ -152,24 +89,8 @@ bool Waiter::WaitRelativeTimeout(KernelTimeout t) {
return true; // Consumed a wakeup, we are done.
}
- auto relative_timeout = t.MakeRelativeTimespec();
- if (!first_pass) {
- MaybeBecomeIdle();
-
- // Adjust relative_timeout for `Poke()`s.
- struct timespec now;
- ABSL_RAW_CHECK(clock_gettime(CLOCK_MONOTONIC, &now) == 0,
- "clock_gettime() failed");
- // If TimespecSubstract(now, start) returns false, then the clock isn't
- // truly monotonic.
- if (TimespecSubtract(now, start)) {
- if (!TimespecSubtract(relative_timeout, now)) {
- return false; // Timeout.
- }
- }
- }
-
- const int err = Futex::WaitRelativeTimeout(&futex_, 0, &relative_timeout);
+ if (!first_pass) MaybeBecomeIdle();
+ const int err = Futex::WaitUntil(&futex_, 0, t);
if (err != 0) {
if (err == -EINTR || err == -EWOULDBLOCK) {
// Do nothing, the loop will retry.
@@ -183,23 +104,6 @@ bool Waiter::WaitRelativeTimeout(KernelTimeout t) {
}
}
-#else // CLOCK_MONOTONIC
-
-// No support for CLOCK_MONOTONIC.
-// KernelTimeout will automatically convert to an absolute timeout.
-bool Waiter::WaitRelativeTimeout(KernelTimeout t) {
- return WaitAbsoluteTimeout(t);
-}
-
-#endif // CLOCK_MONOTONIC
-
-bool Waiter::Wait(KernelTimeout t) {
- if (t.is_absolute_timeout()) {
- return WaitAbsoluteTimeout(t);
- }
- return WaitRelativeTimeout(t);
-}
-
void Waiter::Post() {
if (futex_.fetch_add(1, std::memory_order_release) == 0) {
// We incremented from 0, need to wake a potential waiter.