From: Nathan Bronson Date: Tue, 16 Dec 2014 18:34:47 +0000 (-0800) Subject: fix Futex when steady_clock and system_clock precisions differ X-Git-Tag: v0.22.0~99 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1a608d58e87bb9e0c006918293ec9b7e759b11e2;p=folly.git fix Futex when steady_clock and system_clock precisions differ Summary: To handle the strange relationship between steady_clock and system_clock (on some platforms these represent only one type, on some platforms they are separate) Futex::futexWaitUntil converts the deadline to a duration and back. On Xcode 6 system_clock is measured in microseconds and steady_clock in nanoseconds, resulting in a compilation failure. This diff fixes it. Test Plan: 1. compile snippet manually using Xcode 2. new unit test that causes the same implicit conversion failure in a slightly different way Reviewed By: mssarang@fb.com Subscribers: trunkagent, folly-diffs@ FB internal diff: D1740903 Tasks: 5831196 Signature: t1:1740903:1418754770:32c999abf1dc87415ffebf45083a903abbded9f2 --- diff --git a/folly/detail/Futex.h b/folly/detail/Futex.h index fe61d0e6..a38b4423 100644 --- a/folly/detail/Futex.h +++ b/folly/detail/Futex.h @@ -80,12 +80,24 @@ struct Futex : Atom, boost::noncopyable { "futexWaitUntil only knows std::chrono::{system_clock,steady_clock}"); assert((std::is_same::value) || Clock::is_steady); - auto duration = absTime.time_since_epoch(); + // We launder the clock type via a std::chrono::duration so that we + // can compile both the true and false branch. Tricky case is when + // steady_clock has a higher precision than system_clock (Xcode 6, + // for example), for which time_point construction + // refuses to do an implicit duration conversion. (duration is + // happy to implicitly convert its denominator causing overflow, but + // refuses conversion that might cause truncation.) We use explicit + // duration_cast to work around this. Truncation does not actually + // occur (unless Duration != Clock::duration) because the missing + // implicit conversion is in the untaken branch. + Duration absTimeDuration = absTime.time_since_epoch(); if (std::is_same::value) { - time_point absSystemTime(duration); + time_point absSystemTime( + duration_cast(absTimeDuration)); return futexWaitImpl(expected, &absSystemTime, nullptr, waitMask); } else { - time_point absSteadyTime(duration); + time_point absSteadyTime( + duration_cast(absTimeDuration)); return futexWaitImpl(expected, nullptr, &absSteadyTime, waitMask); } } diff --git a/folly/test/FutexTest.cpp b/folly/test/FutexTest.cpp index 3c5c63d7..71392bfe 100644 --- a/folly/test/FutexTest.cpp +++ b/folly/test/FutexTest.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -28,6 +29,7 @@ using namespace folly::detail; using namespace folly::test; +using namespace std; using namespace std::chrono; typedef DeterministicSchedule DSched; @@ -54,7 +56,7 @@ void run_basic_tests() { DSched::join(thr); } -template class Atom, typename Clock> +template class Atom, typename Clock, typename Duration> void liveClockWaitUntilTests() { Futex f(0); @@ -62,7 +64,8 @@ void liveClockWaitUntilTests() { auto fp = &f; // workaround for t5336595 auto thrA = DSched::thread([fp,stress]{ while (true) { - auto deadline = Clock::now() + microseconds(1 << (stress % 20)); + auto deadline = time_point_cast( + Clock::now() + microseconds(1 << (stress % 20))); auto res = fp->futexWaitUntil(0, deadline); EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::AWOKEN); if (res == FutexResult::AWOKEN) { @@ -98,8 +101,11 @@ void deterministicAtomicWaitUntilTests() { template class Atom> void run_wait_until_tests() { - liveClockWaitUntilTests(); - liveClockWaitUntilTests(); + liveClockWaitUntilTests(); + liveClockWaitUntilTests(); + + typedef duration picoseconds; + liveClockWaitUntilTests(); } template <>