Commit 1a608d58 authored by Nathan Bronson's avatar Nathan Bronson Committed by JoelMarcey

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
parent f2ac9a5c
......@@ -80,12 +80,24 @@ struct Futex : Atom<uint32_t>, boost::noncopyable {
"futexWaitUntil only knows std::chrono::{system_clock,steady_clock}");
assert((std::is_same<Clock, system_clock>::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<system_clock> 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<Clock, system_clock>::value) {
time_point<system_clock> absSystemTime(duration);
time_point<system_clock> absSystemTime(
duration_cast<system_clock::duration>(absTimeDuration));
return futexWaitImpl(expected, &absSystemTime, nullptr, waitMask);
} else {
time_point<steady_clock> absSteadyTime(duration);
time_point<steady_clock> absSteadyTime(
duration_cast<steady_clock::duration>(absTimeDuration));
return futexWaitImpl(expected, nullptr, &absSteadyTime, waitMask);
}
}
......
......@@ -19,6 +19,7 @@
#include <chrono>
#include <functional>
#include <ratio>
#include <thread>
#include <gflags/gflags.h>
......@@ -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 <template<typename> class Atom, typename Clock>
template <template<typename> class Atom, typename Clock, typename Duration>
void liveClockWaitUntilTests() {
Futex<Atom> 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<Duration>(
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<template<typename> class Atom>
void run_wait_until_tests() {
liveClockWaitUntilTests<Atom, system_clock>();
liveClockWaitUntilTests<Atom, steady_clock>();
liveClockWaitUntilTests<Atom, system_clock, system_clock::duration>();
liveClockWaitUntilTests<Atom, steady_clock, steady_clock::duration>();
typedef duration<int64_t, pico> picoseconds;
liveClockWaitUntilTests<Atom, system_clock, picoseconds>();
}
template <>
......
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