Commit 0372af19 by Derek Mauro Committed by Copybara-Service

Add KernelTimeout methods that convert the timeout to the

std::chrono methods used by std::condition_variable.

A followup change will add an implemention of
synchronization_internal::Waiter that can use
std:mutex/std::condition_variable to implement the per-thread
semaphore that absl::Mutex waits on. This implementation may at some
point become the default on platforms such as Windows where there
doesn't seem to be an easy way of supporting real absolute timeouts. In
this case we can defer to their standard library to implement correct
support.
PiperOrigin-RevId: 510204786
Change-Id: Icf4d695013fd060abbd53dae23e71ea36f731565
parent 2d4c6872
......@@ -15,6 +15,7 @@
#include "absl/synchronization/internal/kernel_timeout.h"
#include <algorithm>
#include <chrono> // NOLINT(build/c++11)
#include <cstdint>
#include <ctime>
#include <limits>
......@@ -163,6 +164,46 @@ KernelTimeout::DWord KernelTimeout::InMillisecondsFromNow() const {
return DWord{0};
}
std::chrono::time_point<std::chrono::system_clock>
KernelTimeout::ToChronoTimePoint() const {
if (!has_timeout()) {
return std::chrono::time_point<std::chrono::system_clock>::max();
}
// The cast to std::microseconds is because (on some platforms) the
// std::ratio used by std::chrono::steady_clock doesn't convert to
// std::nanoseconds, so it doesn't compile.
auto micros = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::nanoseconds(RawNanos()));
if (is_relative_timeout()) {
auto now = std::chrono::system_clock::now();
if (micros >
std::chrono::time_point<std::chrono::system_clock>::max() - now) {
// Overflow.
return std::chrono::time_point<std::chrono::system_clock>::max();
}
return now + micros;
}
return std::chrono::system_clock::from_time_t(0) + micros;
}
std::chrono::nanoseconds KernelTimeout::ToChronoDuration() const {
if (!has_timeout()) {
return std::chrono::nanoseconds::max();
}
if (is_absolute_timeout()) {
auto d = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::nanoseconds(RawNanos()) -
(std::chrono::system_clock::now() -
std::chrono::system_clock::from_time_t(0)));
if (d < std::chrono::nanoseconds(0)) {
d = std::chrono::nanoseconds(0);
}
return d;
}
return std::chrono::nanoseconds(RawNanos());
}
} // namespace synchronization_internal
ABSL_NAMESPACE_END
} // namespace absl
......@@ -16,6 +16,7 @@
#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
#include <algorithm>
#include <chrono> // NOLINT(build/c++11)
#include <cstdint>
#include <ctime>
#include <limits>
......@@ -95,6 +96,20 @@ class KernelTimeout {
typedef unsigned long DWord; // NOLINT
DWord InMillisecondsFromNow() const;
// Convert to std::chrono::time_point for interfaces that expect an absolute
// timeout, like std::condition_variable::wait_until(). If !has_timeout() or
// is_relative_timeout(), attempts to convert to a reasonable absolute
// timeout, but callers should test has_timeout() and is_relative_timeout()
// and prefer to use a more appropriate interface.
std::chrono::time_point<std::chrono::system_clock> ToChronoTimePoint() const;
// Convert to std::chrono::time_point for interfaces that expect a relative
// timeout, like std::condition_variable::wait_for(). If !has_timeout() or
// is_absolute_timeout(), attempts to convert to a reasonable relative
// timeout, but callers should test has_timeout() and is_absolute_timeout()
// and prefer to use a more appropriate interface.
std::chrono::nanoseconds ToChronoDuration() const;
private:
// Internal representation.
// - If the value is kNoTimeout, then the timeout is infinite, and
......
......@@ -14,6 +14,7 @@
#include "absl/synchronization/internal/kernel_timeout.h"
#include <chrono> // NOLINT(build/c++11)
#include <limits>
#include "gtest/gtest.h"
......@@ -72,6 +73,11 @@ TEST(KernelTimeout, FiniteTimes) {
EXPECT_LE(absl::AbsDuration(absl::Milliseconds(t.InMillisecondsFromNow()) -
std::max(duration, absl::ZeroDuration())),
absl::Milliseconds(5));
EXPECT_LE(absl::AbsDuration(absl::FromChrono(t.ToChronoTimePoint()) - when),
absl::Microseconds(1));
EXPECT_LE(absl::AbsDuration(absl::FromChrono(t.ToChronoDuration()) -
std::max(duration, absl::ZeroDuration())),
kTimingBound);
}
}
......@@ -90,6 +96,9 @@ TEST(KernelTimeout, InfiniteFuture) {
absl::Now() + absl::Hours(100000));
EXPECT_EQ(t.InMillisecondsFromNow(),
std::numeric_limits<KernelTimeout::DWord>::max());
EXPECT_EQ(t.ToChronoTimePoint(),
std::chrono::time_point<std::chrono::system_clock>::max());
EXPECT_GE(t.ToChronoDuration(), std::chrono::nanoseconds::max());
}
TEST(KernelTimeout, DefaultConstructor) {
......@@ -108,6 +117,9 @@ TEST(KernelTimeout, DefaultConstructor) {
absl::Now() + absl::Hours(100000));
EXPECT_EQ(t.InMillisecondsFromNow(),
std::numeric_limits<KernelTimeout::DWord>::max());
EXPECT_EQ(t.ToChronoTimePoint(),
std::chrono::time_point<std::chrono::system_clock>::max());
EXPECT_GE(t.ToChronoDuration(), std::chrono::nanoseconds::max());
}
TEST(KernelTimeout, TimeMaxNanos) {
......@@ -126,6 +138,9 @@ TEST(KernelTimeout, TimeMaxNanos) {
absl::Now() + absl::Hours(100000));
EXPECT_EQ(t.InMillisecondsFromNow(),
std::numeric_limits<KernelTimeout::DWord>::max());
EXPECT_EQ(t.ToChronoTimePoint(),
std::chrono::time_point<std::chrono::system_clock>::max());
EXPECT_GE(t.ToChronoDuration(), std::chrono::nanoseconds::max());
}
TEST(KernelTimeout, Never) {
......@@ -144,6 +159,9 @@ TEST(KernelTimeout, Never) {
absl::Now() + absl::Hours(100000));
EXPECT_EQ(t.InMillisecondsFromNow(),
std::numeric_limits<KernelTimeout::DWord>::max());
EXPECT_EQ(t.ToChronoTimePoint(),
std::chrono::time_point<std::chrono::system_clock>::max());
EXPECT_GE(t.ToChronoDuration(), std::chrono::nanoseconds::max());
}
TEST(KernelTimeout, InfinitePast) {
......@@ -157,6 +175,9 @@ TEST(KernelTimeout, InfinitePast) {
absl::ZeroDuration());
EXPECT_LE(absl::FromUnixNanos(t.MakeAbsNanos()), absl::FromUnixNanos(1));
EXPECT_EQ(t.InMillisecondsFromNow(), KernelTimeout::DWord{0});
EXPECT_LT(t.ToChronoTimePoint(), std::chrono::system_clock::from_time_t(0) +
std::chrono::seconds(1));
EXPECT_EQ(t.ToChronoDuration(), std::chrono::nanoseconds(0));
}
TEST(KernelTimeout, FiniteDurations) {
......@@ -186,6 +207,10 @@ TEST(KernelTimeout, FiniteDurations) {
absl::Milliseconds(5));
EXPECT_LE(absl::Milliseconds(t.InMillisecondsFromNow()) - duration,
absl::Milliseconds(5));
EXPECT_LE(absl::AbsDuration(absl::Now() + duration -
absl::FromChrono(t.ToChronoTimePoint())),
kTimingBound);
EXPECT_EQ(absl::FromChrono(t.ToChronoDuration()), duration);
}
}
......@@ -218,6 +243,10 @@ TEST(KernelTimeout, NegativeDurations) {
absl::AbsDuration(absl::Now() - absl::FromUnixNanos(t.MakeAbsNanos())),
absl::Milliseconds(5));
EXPECT_EQ(t.InMillisecondsFromNow(), KernelTimeout::DWord{0});
EXPECT_LE(absl::AbsDuration(absl::Now() -
absl::FromChrono(t.ToChronoTimePoint())),
absl::Milliseconds(5));
EXPECT_EQ(t.ToChronoDuration(), std::chrono::nanoseconds(0));
}
}
......@@ -236,6 +265,9 @@ TEST(KernelTimeout, InfiniteDuration) {
absl::Now() + absl::Hours(100000));
EXPECT_EQ(t.InMillisecondsFromNow(),
std::numeric_limits<KernelTimeout::DWord>::max());
EXPECT_EQ(t.ToChronoTimePoint(),
std::chrono::time_point<std::chrono::system_clock>::max());
EXPECT_GE(t.ToChronoDuration(), std::chrono::nanoseconds::max());
}
TEST(KernelTimeout, DurationMaxNanos) {
......@@ -254,6 +286,9 @@ TEST(KernelTimeout, DurationMaxNanos) {
absl::Now() + absl::Hours(100000));
EXPECT_EQ(t.InMillisecondsFromNow(),
std::numeric_limits<KernelTimeout::DWord>::max());
EXPECT_EQ(t.ToChronoTimePoint(),
std::chrono::time_point<std::chrono::system_clock>::max());
EXPECT_GE(t.ToChronoDuration(), std::chrono::nanoseconds::max());
}
TEST(KernelTimeout, OverflowNanos) {
......@@ -273,6 +308,9 @@ TEST(KernelTimeout, OverflowNanos) {
absl::Now() + absl::Hours(100000));
EXPECT_LE(absl::Milliseconds(t.InMillisecondsFromNow()) - duration,
absl::Milliseconds(5));
EXPECT_GT(t.ToChronoTimePoint(),
std::chrono::system_clock::now() + std::chrono::hours(100000));
EXPECT_GT(t.ToChronoDuration(), std::chrono::hours(100000));
}
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment