timeSpecFromTimePoint(time_point<Clock> absTime)
{
auto duration = absTime.time_since_epoch();
+ if (duration.count() < 0) {
+ // kernel timespec_valid requires non-negative seconds and nanos in [0,1G)
+ duration = Clock::duration::zero();
+ }
auto secs = duration_cast<seconds>(duration);
auto nanos = duration_cast<nanoseconds>(duration - secs);
struct timespec result = { secs.count(), nanos.count() };
return FutexResult::VALUE_CHANGED;
default:
assert(false);
- // EACCESS, EFAULT, or EINVAL. All of these mean *addr point to
- // invalid memory (or I misunderstand the API). We can either
+ // EINVAL, EACCESS, or EFAULT. EINVAL means there was an invalid
+ // op (should be impossible) or an invalid timeout (should have
+ // been sanitized by timeSpecFromTimePoint). EACCESS or EFAULT
+ // means *addr points to invalid memory, which is unlikely because
+ // the caller should have segfaulted already. We can either
// crash, or return a value that lets the process continue for
// a bit. We choose the latter. VALUE_CHANGED probably turns the
// caller into a spin lock.
auto fp = &f; // workaround for t5336595
auto thrA = DSched::thread([fp,stress]{
while (true) {
- auto deadline = time_point_cast<Duration>(
+ const auto deadline = time_point_cast<Duration>(
Clock::now() + microseconds(1 << (stress % 20)));
- auto res = fp->futexWaitUntil(0, deadline);
+ const auto res = fp->futexWaitUntil(0, deadline);
EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::AWOKEN);
if (res == FutexResult::AWOKEN) {
break;
DSched::join(thrA);
}
- auto start = Clock::now();
- EXPECT_EQ(f.futexWaitUntil(0, start + milliseconds(100)),
- FutexResult::TIMEDOUT);
- LOG(INFO) << "Futex wait timed out after waiting for "
- << duration_cast<milliseconds>(Clock::now() - start).count()
- << "ms, should be ~100ms";
+ {
+ const auto start = Clock::now();
+ const auto deadline = time_point_cast<Duration>(start + milliseconds(100));
+ EXPECT_EQ(f.futexWaitUntil(0, deadline), FutexResult::TIMEDOUT);
+ LOG(INFO) << "Futex wait timed out after waiting for "
+ << duration_cast<milliseconds>(Clock::now() - start).count()
+ << "ms using clock with " << Duration::period::den
+ << " precision, should be ~100ms";
+ }
+
+ {
+ const auto start = Clock::now();
+ const auto deadline = time_point_cast<Duration>(
+ start - 2 * start.time_since_epoch());
+ EXPECT_EQ(f.futexWaitUntil(0, deadline), FutexResult::TIMEDOUT);
+ LOG(INFO) << "Futex wait with invalid deadline timed out after waiting for "
+ << duration_cast<milliseconds>(Clock::now() - start).count()
+ << "ms using clock with " << Duration::period::den
+ << " precision, should be ~0ms";
+ }
}
template <typename Clock>
// Futex wait must eventually fail with either FutexResult::TIMEDOUT or
// FutexResult::INTERRUPTED
- auto res = f.futexWaitUntil(0, Clock::now() + milliseconds(100));
+ const auto res = f.futexWaitUntil(0, Clock::now() + milliseconds(100));
EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::INTERRUPTED);
}
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>();
+ typedef duration<int64_t, std::ratio<1, 10000000>> decimicroseconds;
+ liveClockWaitUntilTests<Atom, system_clock, decimicroseconds>();
}
template <>
struct timespec ts;
const int maxIters = 1000;
int iter = 0;
- uint64_t delta = 10000000 /* 10 ms */;
+ const uint64_t delta = 10000000 /* 10 ms */;
/** The following loop is only to make the test more robust in the presence of
* clock adjustments that can occur. We just run the loop maxIter times and
* for the time_points */
EXPECT_TRUE(steady_clock::is_steady);
- uint64_t A = duration_cast<nanoseconds>(steady_clock::now()
- .time_since_epoch()).count();
+ const uint64_t A = duration_cast<nanoseconds>(steady_clock::now()
+ .time_since_epoch()).count();
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
- uint64_t B = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+ const uint64_t B = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
- uint64_t C = duration_cast<nanoseconds>(steady_clock::now()
- .time_since_epoch()).count();
+ const uint64_t C = duration_cast<nanoseconds>(steady_clock::now()
+ .time_since_epoch()).count();
EXPECT_TRUE(A <= B && B <= C);
}