} // namespace filesystem
#endif // C++17 && HOSTED
+#if defined _GLIBCXX_USE_NANOSLEEP || defined _GLIBCXX_USE_CLOCK_REALTIME \
+ || defined _GLIBCXX_HAS_GTHREADS
+namespace chrono
+{
+/// @cond undocumented
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ // Convert a chrono::duration to a relative time represented as timespec
+ // (e.g. for use with nanosleep).
+ template<typename _Rep, typename _Period>
+ [[__nodiscard__]] _GLIBCXX14_CONSTEXPR inline
+ struct ::timespec
+ __to_timeout_timespec(const duration<_Rep, _Period>& __d)
+ {
+ struct ::timespec __ts{};
+
+ if (__d < __d.zero()) // Negative timeouts don't make sense.
+ return __ts;
+
+ if constexpr (ratio_greater<_Period, ratio<1>>::value
+ || treat_as_floating_point<_Rep>::value)
+ {
+ // Converting from e.g. chrono::hours::max() to chrono::seconds
+ // would evaluate LLONG_MAX * 3600 which would overflow.
+ // Limit to chrono::seconds::max().
+ chrono::duration<double> __fmax(chrono::seconds::max());
+ if (__d > __fmax) [[__unlikely__]]
+ return chrono::__to_timeout_timespec(chrono::seconds::max());
+ }
+
+ auto __s = chrono::duration_cast<chrono::seconds>(__d);
+
+ if constexpr (is_integral<time_t>::value) // POSIX.1-2001 allows floating
+ {
+ // Also limit to time_t maximum (only relevant for 32-bit time_t).
+ constexpr auto __tmax = numeric_limits<time_t>::max();
+ if (__s.count() > __tmax) [[__unlikely__]]
+ {
+ __ts.tv_sec = __tmax;
+ return __ts;
+ }
+ }
+
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__d - __s);
+
+ if constexpr (treat_as_floating_point<_Rep>::value)
+ if (__ns.count() > 999999999) [[__unlikely__]]
+ __ns = chrono::nanoseconds(999999999);
+
+ __ts.tv_sec = static_cast<time_t>(__s.count());
+ __ts.tv_nsec = static_cast<long>(__ns.count());
+ return __ts;
+ }
+#pragma GCC diagnostic pop
+
+ // Convert a chrono::time_point to an absolute time represented as timespec.
+ // All times before the epoch get converted to the epoch, so this assumes
+ // that we only use it for clocks where that's true.
+ // It should be safe to use this for system_clock and steady_clock.
+ template<typename _Clock, typename _Dur>
+ [[__nodiscard__]] _GLIBCXX14_CONSTEXPR inline
+ struct ::timespec
+ __to_timeout_timespec(const time_point<_Clock, _Dur>& __t)
+ {
+ return chrono::__to_timeout_timespec(__t.time_since_epoch());
+ }
+
+/// @endcond
+} // namespace chrono
+#endif // USE_NANOSLEEP || USE_CLOCK_REALTIME || HAS_GTHREADS
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#else
#include <errno.h> // EBUSY
+#include <bits/chrono.h>
#include <bits/functexcept.h>
#include <bits/gthr.h>
__gthread_cond_t _M_cond;
#endif
};
- /// @endcond
+namespace chrono
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ // Convert a time_point to an absolute time represented as __gthread_time_t
+ // (which is typically just a typedef for struct timespec).
+ template<typename _Clock, typename _Dur>
+ [[__nodiscard__]] _GLIBCXX14_CONSTEXPR inline
+ __gthread_time_t
+ __to_timeout_gthread_time_t(const time_point<_Clock, _Dur>& __t)
+ {
+ auto __ts = chrono::__to_timeout_timespec(__t.time_since_epoch());
+ if constexpr (is_same<::timespec, __gthread_time_t>::value)
+ return __ts;
+ else if constexpr (is_convertible<::timespec, __gthread_time_t>::value)
+ return __ts;
+ else if constexpr (is_scalar<__gthread_time_t>::value) // Assume seconds:
+ return static_cast<__gthread_time_t>(__ts.tv_sec);
+ else // Assume this works and the members are in the correct order:
+ return __gthread_time_t{ __ts.tv_sec, __ts.tv_nsec };
+ }
+#pragma GCC diagnostic pop
+}
+ /// @endcond
#endif // _GLIBCXX_HAS_GTHREADS
/// Do not acquire ownership of the mutex.
#if __cplusplus >= 201103L
#include <bits/chrono.h> // std::chrono::*
+#include <ext/numeric_traits.h> // __int_traits
#ifdef _GLIBCXX_USE_NANOSLEEP
# include <cerrno> // errno, EINTR
{
#ifndef _GLIBCXX_NO_SLEEP
-#ifndef _GLIBCXX_USE_NANOSLEEP
- void
- __sleep_for(chrono::seconds, chrono::nanoseconds);
-#endif
-
/// this_thread::sleep_for
template<typename _Rep, typename _Period>
inline void
{
if (__rtime <= __rtime.zero())
return;
- auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
+
+ struct timespec __ts = chrono::__to_timeout_timespec(__rtime);
#ifdef _GLIBCXX_USE_NANOSLEEP
- struct ::timespec __ts =
- {
- static_cast<std::time_t>(__s.count()),
- static_cast<long>(__ns.count())
- };
while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
{ }
#else
- __sleep_for(__s, __ns);
+ using chrono::seconds;
+ using chrono::nanoseconds;
+ void __sleep_for(seconds __s, nanoseconds __ns);
+ __sleep_for(seconds(__ts.tv_sec), nanoseconds(__ts.tv_nsec));
#endif
}
__wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<steady_clock, _Dur>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
_M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts);
return (steady_clock::now() < __atime
__wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<system_clock, _Dur>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
_M_cond.wait_until(*__lock.mutex(), __ts);
return (system_clock::now() < __atime
_M_try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts = {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
return static_cast<_Derived*>(this)->_M_timedlock(__ts);
}
_M_try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts = {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC,
__ts);
}
try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = __glibcxx_rwlock_timedwrlock(&_M_rwlock, &__ts);
// On self-deadlock, we just fail to acquire the lock. Technically,
// the program violated the precondition.
try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = pthread_rwlock_clockwrlock(&_M_rwlock, CLOCK_MONOTONIC,
&__ts);
// On self-deadlock, we just fail to acquire the lock. Technically,
try_lock_shared_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret;
// Unlike for lock(), we are not allowed to throw an exception so if
try_lock_shared_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = pthread_rwlock_clockrdlock(&_M_rwlock, CLOCK_MONOTONIC,
&__ts);
// On self-deadlock, we just fail to acquire the lock. Technically,
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace this_thread
{
+namespace
+{
+ // returns min(s, Dur::max())
+ template<typename Dur>
+ inline chrono::seconds
+ limit(chrono::seconds s)
+ {
+ static_assert(ratio_equal<typename Dur::period, ratio<1>>::value,
+ "period must be seconds to avoid potential overflow");
+
+ if (s > Dur::max()) [[__unlikely__]]
+ s = chrono::duration_cast<chrono::seconds>(Dur::max());
+ return s;
+ }
+}
+
void
__sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
{
#ifdef _GLIBCXX_USE_NANOSLEEP
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ if constexpr (is_integral<time_t>::value) // POSIX.1-2001 allows floating
+ __s = limit<chrono::duration<time_t>>(__s);
+
struct ::timespec __ts =
{
static_cast<std::time_t>(__s.count()),
const auto target = chrono::steady_clock::now() + __s + __ns;
while (true)
{
+ __s = limit<chrono::duration<unsigned>>(__s);
+
unsigned secs = __s.count();
if (__ns.count() > 0)
{
break;
__s = chrono::duration_cast<chrono::seconds>(target - now);
__ns = chrono::duration_cast<chrono::nanoseconds>(target - (now + __s));
- }
+ }
#elif defined(_GLIBCXX_USE_WIN32_SLEEP)
- unsigned long ms = __ns.count() / 1000000;
- if (__ns.count() > 0 && ms == 0)
- ms = 1;
- ::Sleep(chrono::milliseconds(__s).count() + ms);
+
+ // Can't use limit<chrono::milliseconds>(__s) here because it would
+ // multiply __s by 1000 which could overflow.
+ // Limit to milliseconds::max() and truncate to seconds:
+ chrono::milliseconds ms = chrono::milliseconds::max();
+ if (__s < chrono::duration_cast<chrono::seconds>(ms))
+ {
+ ms = __s;
+ ms += chrono::__detail::ceil<chrono::milliseconds>(__ns);
+ }
+
+ // Use Sleep(DWORD millis) where DWORD is uint32_t.
+ constexpr chrono::milliseconds max_sleep(INFINITE - 1u);
+ while (ms > max_sleep)
+ {
+ ::Sleep(max_sleep.count());
+ ms -= max_sleep;
+ }
+
+ ::Sleep(ms.count());
#endif
}
}
__platform_wait_t __old,
const __wait_clock_t::time_point& __atime) noexcept
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- struct timespec __rt =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ struct timespec __rt = chrono::__to_timeout_timespec(__atime);
if (syscall (SYS_futex, __addr,
static_cast<int>(__futex_wait_flags::__wait_bitset_private),
__cond_wait_until(__condvar& __cv, mutex& __mx,
const __wait_clock_t::time_point& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
if constexpr (is_same_v<chrono::steady_clock, __wait_clock_t>)
--- /dev/null
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+
+// PR libstdc++/113327
+// std::sleep_for(std::chrono::hours::max()) returns immediately
+
+#include <thread>
+#include <chrono>
+#include <cstdlib>
+#include <csignal>
+
+int main()
+{
+ std::thread sleepy([] {
+ // Rather than overflowing to a negative value, the timeout should be
+ // truncated to seconds::max() and so sleep for 292 billion years.
+ std::this_thread::sleep_for(std::chrono::minutes::max());
+ // This should not happen:
+ throw 1;
+ });
+ // Give the new thread a chance to start sleeping:
+ std::this_thread::yield();
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ // If we get here without the other thread throwing an exception
+ // then it should be sleeping peacefully, so the test passed.
+ // pthread_kill(sleepy.native_handle(), SIGINT);
+ std::_Exit(0);
+}