aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/std/chrono
diff options
context:
space:
mode:
authorMike Crowe <mac@mcrowe.com>2020-09-11 14:25:00 +0100
committerJonathan Wakely <jwakely@redhat.com>2020-09-11 14:28:50 +0100
commitf9ddb696a289cc48d24d3d23c0b324cb88de9573 (patch)
tree857b634df275db37f0ade0a6670b49ad4e9a79e8 /libstdc++-v3/include/std/chrono
parentb9faa3301c523c2c165387da4b19e659f7362a92 (diff)
downloadgcc-f9ddb696a289cc48d24d3d23c0b324cb88de9573.zip
gcc-f9ddb696a289cc48d24d3d23c0b324cb88de9573.tar.gz
gcc-f9ddb696a289cc48d24d3d23c0b324cb88de9573.tar.bz2
libstdc++: Avoid rounding errors in std::future::wait_* [PR 91486]
Convert the specified duration to the target clock's duration type before adding it to the current time in __atomic_futex_unsigned::_M_load_when_equal_for and _M_load_when_equal_until. This removes the risk of the timeout being rounded down to the current time resulting in there being no wait at all when the duration type lacks sufficient precision to hold the steady_clock current time. Rather than using the style of fix from PR68519, let's expose the C++17 std::chrono::ceil function as std::chrono::__detail::ceil so that it can be used in code compiled with earlier standards versions and simplify the fix. This was suggested by John Salmon in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91486#c5 . This problem has become considerably less likely to trigger since I switched the __atomic__futex_unsigned::__clock_t reference clock from system_clock to steady_clock and added the loop, but the consequences of triggering it have changed too. By my calculations it takes just over 194 days from the epoch for the current time not to be representable in a float. This means that system_clock is always subject to the problem (with the standard 1970 epoch) whereas steady_clock with float duration only runs out of resolution machine has been running for that long (assuming the Linux implementation of CLOCK_MONOTONIC.) The recently-added loop in __atomic_futex_unsigned::_M_load_when_equal_until turns this scenario into a busy wait. Unfortunately the combination of both of these things means that it's not possible to write a test case for this occurring in _M_load_when_equal_until as it stands. libstdc++-v3/ChangeLog: PR libstdc++/91486 * include/bits/atomic_futex.h (__atomic_futex_unsigned::_M_load_when_equal_for) (__atomic_futex_unsigned::_M_load_when_equal_until): Use __detail::ceil to convert delta to the reference clock duration type to avoid resolution problems. * include/std/chrono (__detail::ceil): Move implementation of std::chrono::ceil into private namespace so that it's available to pre-C++17 code. * testsuite/30_threads/async/async.cc (test_pr91486): Test __atomic_futex_unsigned::_M_load_when_equal_for.
Diffstat (limited to 'libstdc++-v3/include/std/chrono')
-rw-r--r--libstdc++-v3/include/std/chrono19
1 files changed, 15 insertions, 4 deletions
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 9b9fd2b..893d1f6 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -329,6 +329,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
#endif // C++20
+ // We want to use ceil even when compiling for earlier standards versions
+ namespace __detail
+ {
+ template<typename _ToDur, typename _Rep, typename _Period>
+ constexpr __enable_if_is_duration<_ToDur>
+ ceil(const duration<_Rep, _Period>& __d)
+ {
+ auto __to = chrono::duration_cast<_ToDur>(__d);
+ if (__to < __d)
+ return __to + _ToDur{1};
+ return __to;
+ }
+ }
+
#if __cplusplus >= 201703L
# define __cpp_lib_chrono 201611
@@ -346,10 +360,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr __enable_if_is_duration<_ToDur>
ceil(const duration<_Rep, _Period>& __d)
{
- auto __to = chrono::duration_cast<_ToDur>(__d);
- if (__to < __d)
- return __to + _ToDur{1};
- return __to;
+ return __detail::ceil<_ToDur>(__d);
}
template <typename _ToDur, typename _Rep, typename _Period>