Skip to content

Commit c3c76a8

Browse files
<condition_variable>: Fixes bad timeout in wait_until with unsigned rep (#3761)
1 parent 5226b57 commit c3c76a8

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

stl/inc/condition_variable

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ public:
9595
#if _HAS_CXX20
9696
static_assert(chrono::is_clock_v<_Clock>, "Clock type required");
9797
#endif // _HAS_CXX20
98-
return wait_for(_Lck, _Abs_time - _Clock::now());
98+
const auto _Now = _Clock::now();
99+
using _Common_duration = decltype(_Abs_time - _Now);
100+
const _Common_duration _Rel_time = (_Abs_time <= _Now) ? _Common_duration::zero() : _Abs_time - _Now;
101+
return wait_for(_Lck, _Rel_time);
99102
}
100103

101104
template <class _Lock, class _Clock, class _Duration, class _Predicate>

tests/std/tests/GH_000685_condition_variable_any/test.cpp

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
#include <chrono>
88
#include <condition_variable>
99
#include <mutex>
10+
#include <type_traits>
1011

1112
using namespace std;
13+
using namespace std::chrono;
1214

1315
namespace {
1416
class my_mutex { // user-defined mutex type
@@ -31,8 +33,8 @@ namespace {
3133
int num_lock = 0;
3234
};
3335

34-
const chrono::nanoseconds interval{20};
35-
const chrono::nanoseconds zero_dur{0};
36+
const nanoseconds interval{20};
37+
const nanoseconds zero_dur{0};
3638

3739
void test_condition_variable_any() { // test wait functions of condition variables
3840
condition_variable_any cnd;
@@ -46,15 +48,40 @@ namespace {
4648
cnd.wait_for(mtx, interval);
4749
assert(mtx.num_locks() == 3);
4850

49-
cnd.wait_until(mtx, chrono::steady_clock::now());
51+
cnd.wait_until(mtx, steady_clock::now());
5052
assert(mtx.num_locks() == 4);
5153

52-
cnd.wait_until(mtx, chrono::steady_clock::now() + interval);
54+
cnd.wait_until(mtx, steady_clock::now() + interval);
5355
assert(mtx.num_locks() == 5);
5456
}
5557
}
58+
59+
void test_condition_variable_any_already_timed_out() {
60+
using unsigned_duration = duration<make_unsigned_t<system_clock::rep>, system_clock::period>;
61+
const auto right_now = time_point_cast<unsigned_duration>(system_clock::now());
62+
const auto yesterday = right_now - hours{24};
63+
assert(yesterday - right_now > system_clock::duration::zero()); // unsigned overflow
64+
65+
my_mutex m;
66+
condition_variable_any cond;
67+
unique_lock<my_mutex> guard(m);
68+
69+
const auto status = cond.wait_until(m, yesterday);
70+
assert(status == cv_status::timeout);
71+
assert(m.num_locks() == 2);
72+
73+
assert(cond.wait_until(m, yesterday, []() { return false; }) == false);
74+
assert(m.num_locks() == 3);
75+
76+
#if _HAS_CXX20
77+
stop_token token;
78+
assert(cond.wait_until(m, token, yesterday, []() { return false; }) == false);
79+
assert(m.num_locks() == 4);
80+
#endif // _HAS_CXX20
81+
}
5682
} // unnamed namespace
5783

5884
int main() {
5985
test_condition_variable_any();
86+
test_condition_variable_any_already_timed_out();
6087
}

0 commit comments

Comments
 (0)