aboutsummaryrefslogtreecommitdiff
path: root/absl/synchronization/internal/sem_waiter.cc
diff options
context:
space:
mode:
authorDerek Mauro <dmauro@google.com>2023-04-08 09:52:09 -0700
committerCopybara-Service <copybara-worker@google.com>2023-04-08 09:52:56 -0700
commit1a72ea7bb8ba27679dd8b179a4671d7d9b099d4b (patch)
treef1e4c715e0e99bbe4206fd91c5b207bb297be4f5 /absl/synchronization/internal/sem_waiter.cc
parent42a3c030c958e6e099162b746ada04792b3a1c67 (diff)
downloadabseil-1a72ea7bb8ba27679dd8b179a4671d7d9b099d4b.tar.gz
abseil-1a72ea7bb8ba27679dd8b179a4671d7d9b099d4b.tar.bz2
abseil-1a72ea7bb8ba27679dd8b179a4671d7d9b099d4b.zip
Synchronization: Support true relative timeouts using the POSIX
proposed standard pthread_cond_clockwait() and sem_clockwait(). These are currently implemented in glibc >= 2.30. These methods take a clock and use an absolute time with reference to that clock, so KernelTimeout now can produce these values. PiperOrigin-RevId: 522824226 Change-Id: Ife98713f6f95d800b1f8e52d5364a3dbebc4f8a6
Diffstat (limited to 'absl/synchronization/internal/sem_waiter.cc')
-rw-r--r--absl/synchronization/internal/sem_waiter.cc34
1 files changed, 28 insertions, 6 deletions
diff --git a/absl/synchronization/internal/sem_waiter.cc b/absl/synchronization/internal/sem_waiter.cc
index 89af5de2..7dd27fb7 100644
--- a/absl/synchronization/internal/sem_waiter.cc
+++ b/absl/synchronization/internal/sem_waiter.cc
@@ -43,12 +43,34 @@ SemWaiter::SemWaiter() : wakeups_(0) {
}
}
-bool SemWaiter::Wait(KernelTimeout t) {
- struct timespec abs_timeout;
- if (t.has_timeout()) {
- abs_timeout = t.MakeAbsTimespec();
+#if defined(__GLIBC__) && \
+ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30))
+#define ABSL_INTERNAL_HAVE_SEM_CLOCKWAIT 1
+#endif
+
+// Calls sem_timedwait() or possibly something else like
+// sem_clockwait() depending on the platform and
+// KernelTimeout requested. The return value is the same as a call to the return
+// value to a call to sem_timedwait().
+int SemWaiter::TimedWait(KernelTimeout t) {
+#ifndef __GOOGLE_GRTE_VERSION__
+ constexpr bool kRelativeTimeoutSupported = true;
+#else
+ constexpr bool kRelativeTimeoutSupported = false;
+#endif
+
+ if (kRelativeTimeoutSupported && 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) {
// Loop until we timeout or consume a wakeup.
// 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.
@@ -73,10 +95,10 @@ bool SemWaiter::Wait(KernelTimeout t) {
if (errno == EINTR) continue;
ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno);
} else {
- if (sem_timedwait(&sem_, &abs_timeout) == 0) break;
+ if (TimedWait(t) == 0) break;
if (errno == EINTR) continue;
if (errno == ETIMEDOUT) return false;
- ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
+ ABSL_RAW_LOG(FATAL, "SemWaiter::TimedWait() failed: %d", errno);
}
}
first_pass = false;