diff --git a/stl/inc/condition_variable b/stl/inc/condition_variable index 6f67941c9d..70248b5965 100644 --- a/stl/inc/condition_variable +++ b/stl/inc/condition_variable @@ -95,7 +95,10 @@ public: #if _HAS_CXX20 static_assert(chrono::is_clock_v<_Clock>, "Clock type required"); #endif // _HAS_CXX20 - return wait_for(_Lck, _Abs_time - _Clock::now()); + const auto _Now = _Clock::now(); + using _Common_duration = decltype(_Abs_time - _Now); + const _Common_duration _Rel_time = (_Abs_time <= _Now) ? _Common_duration::zero() : _Abs_time - _Now; + return wait_for(_Lck, _Rel_time); } template diff --git a/tests/std/tests/GH_000685_condition_variable_any/test.cpp b/tests/std/tests/GH_000685_condition_variable_any/test.cpp index 2d32159823..03ebd7023b 100644 --- a/tests/std/tests/GH_000685_condition_variable_any/test.cpp +++ b/tests/std/tests/GH_000685_condition_variable_any/test.cpp @@ -7,8 +7,10 @@ #include #include #include +#include using namespace std; +using namespace std::chrono; namespace { class my_mutex { // user-defined mutex type @@ -31,8 +33,8 @@ namespace { int num_lock = 0; }; - const chrono::nanoseconds interval{20}; - const chrono::nanoseconds zero_dur{0}; + const nanoseconds interval{20}; + const nanoseconds zero_dur{0}; void test_condition_variable_any() { // test wait functions of condition variables condition_variable_any cnd; @@ -46,15 +48,40 @@ namespace { cnd.wait_for(mtx, interval); assert(mtx.num_locks() == 3); - cnd.wait_until(mtx, chrono::steady_clock::now()); + cnd.wait_until(mtx, steady_clock::now()); assert(mtx.num_locks() == 4); - cnd.wait_until(mtx, chrono::steady_clock::now() + interval); + cnd.wait_until(mtx, steady_clock::now() + interval); assert(mtx.num_locks() == 5); } } + + void test_condition_variable_any_already_timed_out() { + using unsigned_duration = duration, system_clock::period>; + const auto right_now = time_point_cast(system_clock::now()); + const auto yesterday = right_now - hours{24}; + assert(yesterday - right_now > system_clock::duration::zero()); // unsigned overflow + + my_mutex m; + condition_variable_any cond; + unique_lock guard(m); + + const auto status = cond.wait_until(m, yesterday); + assert(status == cv_status::timeout); + assert(m.num_locks() == 2); + + assert(cond.wait_until(m, yesterday, []() { return false; }) == false); + assert(m.num_locks() == 3); + +#if _HAS_CXX20 + stop_token token; + assert(cond.wait_until(m, token, yesterday, []() { return false; }) == false); + assert(m.num_locks() == 4); +#endif // _HAS_CXX20 + } } // unnamed namespace int main() { test_condition_variable_any(); + test_condition_variable_any_already_timed_out(); }