{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ using __gnu_cxx::__int_traits;
+
namespace
{
std::atomic<bool> futex_clock_realtime_unavailable;
auto rel_s = abs_s.count() - now_s;
// Avoid overflows
- if (rel_s > __gnu_cxx::__int_traits<time_t>::__max)
- rel_s = __gnu_cxx::__int_traits<time_t>::__max;
- else if (rel_s < __gnu_cxx::__int_traits<time_t>::__min)
- rel_s = __gnu_cxx::__int_traits<time_t>::__min;
+ if (rel_s > __int_traits<time_t>::__max) [[unlikely]]
+ rel_s = __int_traits<time_t>::__max;
+ else if (rel_s < __int_traits<time_t>::__min) [[unlikely]]
+ rel_s = __int_traits<time_t>::__min;
// Convert the absolute timeout value to a relative timeout
rt.tv_sec = rel_s;
{
if (!futex_clock_realtime_unavailable.load(std::memory_order_relaxed))
{
- struct timespec rt;
- rt.tv_sec = __s.count();
- rt.tv_nsec = __ns.count();
-
// futex sets errno=EINVAL for absolute timeouts before the epoch.
- if (__builtin_expect(rt.tv_sec < 0, false))
+ if (__s.count() < 0)
return false;
+ struct timespec rt;
+ if (__s.count() > __int_traits<time_t>::__max) [[unlikely]]
+ rt.tv_sec = __int_traits<time_t>::__max;
+ else
+ rt.tv_sec = __s.count();
+ rt.tv_nsec = __ns.count();
+
if (syscall (SYS_futex, __addr,
futex_wait_bitset_op | futex_clock_realtime_flag,
__val, &rt, nullptr, futex_bitset_match_any) == -1)
{
if (!futex_clock_monotonic_unavailable.load(std::memory_order_relaxed))
{
- struct timespec rt;
- rt.tv_sec = __s.count();
- rt.tv_nsec = __ns.count();
-
// futex sets errno=EINVAL for absolute timeouts before the epoch.
- if (__builtin_expect(rt.tv_sec < 0, false))
+ if (__s.count() < 0) [[unlikely]]
return false;
+ struct timespec rt;
+ if (__s.count() > __int_traits<time_t>::__max) [[unlikely]]
+ rt.tv_sec = __int_traits<time_t>::__max;
+ else
+ rt.tv_sec = __s.count();
+ rt.tv_nsec = __ns.count();
+
if (syscall (SYS_futex, __addr,
futex_wait_bitset_op | futex_clock_monotonic_flag,
__val, &rt, nullptr, futex_bitset_match_any) == -1)
--- /dev/null
+// { dg-do run }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-effective-target c++11 }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+
+#include <future>
+#include <chrono>
+#include <climits>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+void test01()
+{
+ std::future<void> fut = std::async(std::launch::async, [] {
+ std::this_thread::sleep_for(chrono::seconds(4));
+ });
+
+ // A time in the distant future, but which overflows 32-bit time_t:
+ auto then = chrono::system_clock::now() + chrono::seconds(UINT_MAX + 2LL);
+ auto status = fut.wait_until(then);
+ // The wait_until call should have waited for the result to be ready.
+ // If converting the time_point to time_t overflows, it will timeout.
+ VERIFY(status == std::future_status::ready);
+}
+
+int main()
+{
+ test01();
+}