These tests show that changing the system clock has an effect on std::future::wait_until when using std::chrono::system_clock but not when using std::chrono::steady_clock. Unfortunately these tests have a number of downsides:
1. Nothing that is attempting to keep the clock set correctly (ntpd, systemd-timesyncd) can be running at the same time. 2. The test process requires the CAP_SYS_TIME capability (although, as it's written it checks for being root.) 3. Other processes running concurrently may misbehave when the clock darts back and forth. 4. They are slow to run. As such, I don't think they are suitable for merging. I include them here because I wanted to document how I had tested the changes in the previous commits. --- libstdc++-v3/testsuite/30_threads/async/async.cc | 70 +++++++++++++++++- 1 file changed, 70 insertions(+) diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc index ddd007d..979f5b4 100644 --- a/libstdc++-v3/testsuite/30_threads/async/async.cc +++ b/libstdc++-v3/testsuite/30_threads/async/async.cc @@ -24,6 +24,7 @@ #include <future> #include <testsuite_hooks.h> +#include <sys/time.h> using namespace std; @@ -154,6 +155,71 @@ void test_pr68519() VERIFY( elapsed_steady >= std::chrono::seconds(1) ); } +void perturb_system_clock(const std::chrono::seconds &seconds) +{ + struct timeval tv; + if (gettimeofday(&tv, NULL)) + abort(); + + tv.tv_sec += seconds.count(); + if (settimeofday(&tv, NULL)) + abort(); +} + +// Ensure that advancing CLOCK_REALTIME doesn't make any difference +// when we're waiting on std::chrono::steady_clock. +void test05() +{ + auto const start = chrono::steady_clock::now(); + future<void> f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(10)); + }); + + perturb_system_clock(chrono::seconds(20)); + + std::future_status status; + status = f1.wait_for(std::chrono::seconds(4)); + VERIFY( status == std::future_status::timeout ); + + status = f1.wait_until(start + std::chrono::seconds(6)); + VERIFY( status == std::future_status::timeout ); + + status = f1.wait_until(start + std::chrono::seconds(12)); + VERIFY( status == std::future_status::ready ); + + auto const elapsed = chrono::steady_clock::now() - start; + VERIFY( elapsed >= std::chrono::seconds(10) ); + VERIFY( elapsed < std::chrono::seconds(15) ); + + perturb_system_clock(chrono::seconds(-20)); +} + +// Ensure that advancing CLOCK_REALTIME does make a difference when +// we're waiting on std::chrono::system_clock. +void test06() +{ + auto const start = chrono::system_clock::now(); + auto const start_steady = chrono::steady_clock::now(); + + future<void> f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(5)); + perturb_system_clock(chrono::seconds(60)); + std::this_thread::sleep_for(std::chrono::seconds(5)); + }); + future_status status; + status = f1.wait_until(start + std::chrono::seconds(60)); + VERIFY( status == std::future_status::timeout ); + + auto const elapsed_steady = chrono::steady_clock::now() - start_steady; + VERIFY( elapsed_steady >= std::chrono::seconds(5) ); + VERIFY( elapsed_steady < std::chrono::seconds(10) ); + + status = f1.wait_until(start + std::chrono::seconds(75)); + VERIFY( status == std::future_status::ready ); + + perturb_system_clock(chrono::seconds(-60)); +} + int main() { test01(); @@ -163,5 +229,9 @@ int main() test03<slow_clock>(); test04(); test_pr68519(); + if (geteuid() == 0) { + test05(); + test06(); + } return 0; } -- git-series 0.9.1