* Re: [PATCH] libstdc++: Add C++2a synchronization support
@ 2020-11-21 23:54 David Edelsohn
2020-11-22 1:27 ` Jonathan Wakely
0 siblings, 1 reply; 35+ messages in thread
From: David Edelsohn @ 2020-11-21 23:54 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, GCC Patches, Thomas Rogers
I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
fixes. And a few c++ failures with similar symptoms. I'm not certain
that it is due to this patch, but it's the likely suspect.
FAIL: 17_intro/headers/c++2020/all_attributes.cc (test for excess errors)
FAIL: 17_intro/headers/c++2020/all_no_exceptions.cc (test for excess errors)
FAIL: 17_intro/headers/c++2020/all_no_rtti.cc (test for excess errors)
FAIL: 17_intro/headers/c++2020/all_pedantic_errors.cc (test for excess errors)
FAIL: 17_intro/headers/c++2020/operator_names.cc (test for excess errors)
FAIL: 17_intro/headers/c++2020/stdc++.cc (test for excess errors)
FAIL: 17_intro/headers/c++2020/stdc++_multiple_inclusion.cc (test for
excess errors)
FAIL: 20_util/allocator/rebind_c++20.cc (test for excess errors)
FAIL: 20_util/allocator/requirements/constexpr.cc (test for excess errors)
FAIL: 20_util/allocator/requirements/typedefs_c++20.cc (test for excess errors)
FAIL: 20_util/allocator_traits/header.cc (test for excess errors)
FAIL: 20_util/allocator_traits/members/92878_92947.cc (test for excess errors)
UNRESOLVED: 20_util/allocator_traits/members/92878_92947.cc
compilation failed to produce executable
FAIL: 20_util/assume_aligned/1.cc (test for excess errors)
UNRESOLVED: 20_util/assume_aligned/1.cc compilation failed to produce executable
FAIL: 20_util/assume_aligned/2_neg.cc (test for excess errors)
FAIL: 20_util/assume_aligned/3.cc (test for excess errors)
UNRESOLVED: 20_util/assume_aligned/3.cc scan-assembler-not undefined
FAIL: 20_util/assume_aligned/97132.cc (test for excess errors)
FAIL: 20_util/function_objects/bind_front/2.cc (test for excess errors)
UNRESOLVED: 20_util/function_objects/bind_front/2.cc compilation
failed to produce executable
FAIL: 20_util/pair/comparison_operators/constexpr_c++20.cc (test for
excess errors)
FAIL: 20_util/pair/cons/92878_92947.cc (test for excess errors)
UNRESOLVED: 20_util/pair/cons/92878_92947.cc compilation failed to
produce executable
etc.
The errors all are of the form:
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:125:
error: 'mutex' is not a member of 'std'
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:125:
error: template argument 1 is invalid
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:125:
error: '<expression error>' in namespace 'std' does not name a type
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:126:
error: '__lock_t' does not name a type; did you mean 'clock_t'?
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:132:
error: '__gthread_cond_t' does not name a type; did you mean
'pthread_cond_t'?
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:135:
error: '_M_cond' was not declared in this scope
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:135:
error: '__GTHREAD_COND_INIT_FUNCTION' was not declared in this scope
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:164:
error: '__lock_t' is not a member of 'std::__detail::__waiters'
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:165:
error: '_M_cv' was not declared in this scope
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:165:
error: '__l' was not declared in this scope; did you mean '__lg'?
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:165:
error: '__gthread_cond_wait' was not declared in this scope; did you
mean 'pthread_cond_t'?
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:191:
error: '_M_cv' was not declared in this scope
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++-v3/include/bits/atomic_wait.h:191:
error: '__gthread_cond_broadcast' was not declared in this scope
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++v3/include/bits/atomic_timed_wait.h:144:
error: '__gthread_cond_t' was not declared in this scope; did you mean
'pthread_cond_t'?
/tmp/GCC/powerpc-ibm-aix7.2.3.0/libstdc++v3/include/bits/atomic_timed_wait.h:144:
error: '__cv' was not declared in this scope
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-21 23:54 [PATCH] libstdc++: Add C++2a synchronization support David Edelsohn
@ 2020-11-22 1:27 ` Jonathan Wakely
2020-11-22 12:29 ` Iain Sandoe
2020-11-23 18:30 ` Jonathan Wakely
0 siblings, 2 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-22 1:27 UTC (permalink / raw)
To: David Edelsohn; +Cc: Jonathan Wakely, libstdc++, GCC Patches
[-- Attachment #1: Type: text/plain, Size: 424 bytes --]
On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
<libstdc++@gcc.gnu.org> wrote:
>
> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
> fixes. And a few c++ failures with similar symptoms. I'm not certain
> that it is due to this patch, but it's the likely suspect.
Yes, it's that patch.
This should fix most of those errors, but I haven't finished testing
it, and can't commit it now anyway.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 16676 bytes --]
commit c304e59c2fd8c500232c4c88b632e051e481991f
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sun Nov 22 01:00:46 2020
libstdc++: make atomic waiting depend on gthreads or futexes
libstdc++-v3/ChangeLog:
* include/bits/atomic_wait.h: Do not define anything unless
gthreads or futexes are available.
* include/bits/atomic_timed_wait.h: Likewise.
* include/bits/semaphore_base.h: Likewise.
* include/std/semaphore: Likewise.
* include/bits/atomic_base.h (atomic_flag::wait)
(atomic_flag::notify_one, atomic_flag::notify_all)
(__atomic_base<I>::wait, __atomic_base<I>::notify_one)
(__atomic_base<I>::notify_all, __atomic_base<P*>::wait)
(__atomic_base<P*>::notify_one, __atomic_base<P*>::notify_all)
(__atomic_impl::wait, __atomic_impl::notify_one)
(__atomic_impl::notify_all, __atomic_float::wait)
(__atomic_float::notify_one, __atomic_float::notify_all)
(__atomic_ref::wait, __atomic_ref::notify_one)
(__atomic_ref::notify_all): Only define if gthreads or futexes
are available.
* include/std/atomic (atomic::wait, atomic::notify_one)
(atomic::notify_all): Likewise.
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 7de02f169977..d7db8612889e 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -230,6 +230,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(bool __old,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -252,6 +253,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(&_M_i, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++20
_GLIBCXX_ALWAYS_INLINE void
@@ -603,6 +605,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(__int_type __old,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -625,6 +628,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(&_M_i, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
_GLIBCXX_ALWAYS_INLINE __int_type
@@ -897,6 +901,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(__pointer_type __old,
memory_order __m = memory_order_seq_cst) noexcept
@@ -919,6 +924,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(&_M_p, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
_GLIBCXX_ALWAYS_INLINE __pointer_type
@@ -1010,6 +1016,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE void
wait(const _Tp* __ptr, _Val<_Tp> __old,
@@ -1034,6 +1041,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(__ptr, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
template<typename _Tp>
@@ -1289,6 +1297,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(&_M_fp, __old, __m); }
@@ -1306,6 +1315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(&_M_fp); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
value_type
fetch_add(value_type __i,
@@ -1444,6 +1454,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1461,6 +1472,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
private:
_Tp* _M_ptr;
@@ -1557,6 +1569,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1574,6 +1587,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
value_type
fetch_add(value_type __i,
@@ -1730,6 +1744,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1747,6 +1762,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
value_type
fetch_add(value_type __i,
@@ -1857,6 +1873,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1874,6 +1891,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 405f7e93ca85..b13f8aa12861 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -33,6 +33,7 @@
#pragma GCC system_header
#include <bits/c++config.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/functional_hash.h>
#include <bits/atomic_wait.h>
@@ -286,4 +287,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // _GLIBCXX_ATOMIC_TIMED_WAIT_H
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 7b2682a577ef..a40cff124d7d 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -33,6 +33,7 @@
#pragma GCC system_header
#include <bits/c++config.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/functional_hash.h>
#include <bits/gthr.h>
#include <bits/std_mutex.h>
@@ -106,7 +107,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
- template<typename _Tp>
+ template<typename _Tp>
void
__platform_notify(const _Tp* __addr, bool __all) noexcept
{
@@ -175,11 +176,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
bool
_M_waiting() const noexcept
- {
- __platform_wait_t __res;
- __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
- return __res;
- }
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
void
_M_notify(bool __all) noexcept
@@ -305,4 +306,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // _GLIBCXX_ATOMIC_WAIT_H
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index 78a0b6ba26e6..5e29d3783fe1 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -33,6 +33,7 @@
#pragma GCC system_header
#include <bits/c++config.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/atomic_base.h>
#include <bits/atomic_timed_wait.h>
@@ -161,30 +162,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept
{ return _M_try_acquire_until(__clock_t::now() + __rtime); }
- private:
- sem_t _M_semaphore;
- };
+ private:
+ sem_t _M_semaphore;
+ };
#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
- template<typename _Tp>
- struct __atomic_semaphore
+ template<typename _Tp>
+ struct __atomic_semaphore
+ {
+ static_assert(std::is_integral_v<_Tp>);
+ static_assert(__gnu_cxx::__int_traits<_Tp>::__max
+ <= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+ explicit __atomic_semaphore(_Tp __count) noexcept
+ : _M_counter(__count)
{
- static_assert(std::is_integral_v<_Tp>);
- static_assert(__gnu_cxx::__int_traits<_Tp>::__max
- <= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
- static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+ __glibcxx_assert(__count >= 0 && __count <= _S_max);
+ }
- explicit __atomic_semaphore(_Tp __count) noexcept
- : _M_counter(__count)
- {
- __glibcxx_assert(__count >= 0 && __count <= _S_max);
- }
+ __atomic_semaphore(const __atomic_semaphore&) = delete;
+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
- __atomic_semaphore(const __atomic_semaphore&) = delete;
- __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_counter,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+ std::__atomic_wait(&_M_counter, __old, __pred);
+ }
- _GLIBCXX_ALWAYS_INLINE void
- _M_acquire() noexcept
+ bool
+ _M_try_acquire() noexcept
+ {
+ auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
+ auto const __pred = [this, __old]
+ {
+ if (__old == 0)
+ return false;
+
+ auto __prev = __old;
+ return __atomic_impl::compare_exchange_weak(&this->_M_counter,
+ __prev, __prev - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ return std::__atomic_spin(__pred);
+ }
+
+ template<typename _Clock, typename _Duration>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_until(const chrono::time_point<_Clock,
+ _Duration>& __atime) noexcept
{
auto const __pred = [this]
{
@@ -193,51 +232,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__old == 0)
return false;
return __atomic_impl::compare_exchange_strong(&this->_M_counter,
- __old, __old - 1,
- memory_order::acquire,
- memory_order::release);
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
};
+
auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
- std::__atomic_wait(&_M_counter, __old, __pred);
- }
-
- bool
- _M_try_acquire() noexcept
- {
- auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
- auto const __pred = [this, __old]
- {
- if (__old == 0)
- return false;
-
- auto __prev = __old;
- return __atomic_impl::compare_exchange_weak(&this->_M_counter,
- __prev, __prev - 1,
- memory_order::acquire,
- memory_order::release);
- };
- return std::__atomic_spin(__pred);
- }
-
- template<typename _Clock, typename _Duration>
- _GLIBCXX_ALWAYS_INLINE bool
- _M_try_acquire_until(const chrono::time_point<_Clock,
- _Duration>& __atime) noexcept
- {
- auto const __pred = [this]
- {
- auto __old = __atomic_impl::load(&this->_M_counter,
- memory_order::acquire);
- if (__old == 0)
- return false;
- return __atomic_impl::compare_exchange_strong(&this->_M_counter,
- __old, __old - 1,
- memory_order::acquire,
- memory_order::release);
- };
-
- auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
- return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
+ return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
}
template<typename _Rep, typename _Period>
@@ -299,4 +300,5 @@ template<ptrdiff_t __least_max_value>
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // _GLIBCXX_SEMAPHORE_BASE_H
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 5afe33b41d9b..fe4de244f858 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -165,6 +165,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
void wait(bool __old, memory_order __m = memory_order_seq_cst) const
noexcept
{ _M_base.wait(__old, __m); }
@@ -176,6 +177,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void notify_all() const noexcept
{ _M_base.notify_all(); }
+#endif // GTHREADS || LINUX_FUTEX
#endif
};
@@ -379,6 +381,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m)); }
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{
std::__atomic_wait(&_M_i, __old,
@@ -399,7 +402,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void notify_all() const noexcept
{ std::__atomic_notify(&_M_i, true); }
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // C++20
};
#undef _GLIBCXX20_INIT
@@ -640,6 +644,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
void wait(__pointer_type __old,
memory_order __m = memory_order_seq_cst) noexcept
{ _M_b.wait(__old, __m); }
@@ -651,6 +656,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void notify_all() const noexcept
{ _M_b.notify_all(); }
+#endif // GTHREADS || LINUX_FUTEX
#endif
__pointer_type
fetch_add(ptrdiff_t __d,
@@ -1406,6 +1412,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
template<typename _Tp>
inline void
atomic_wait(const atomic<_Tp>* __a,
@@ -1429,6 +1436,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
atomic_notify_all(atomic<_Tp>* __a) noexcept
{ __a->notify_all(); }
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
// Function templates for atomic_integral and atomic_pointer operations only.
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
index b4facde4ea1f..f4b83ab6ae3f 100644
--- a/libstdc++-v3/include/std/semaphore
+++ b/libstdc++-v3/include/std/semaphore
@@ -32,14 +32,16 @@
#pragma GCC system_header
#if __cplusplus > 201703L
-#define __cpp_lib_semaphore 201907L
#include <bits/semaphore_base.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <ext/numeric_traits.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+#define __cpp_lib_semaphore 201907L
+
template<ptrdiff_t __least_max_value =
__gnu_cxx::__int_traits<ptrdiff_t>::__max>
class counting_semaphore
@@ -88,5 +90,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using binary_semaphore = std::counting_semaphore<1>;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
-#endif // __cplusplus > 201703L
+#endif // GTHREADS || LINUX_FUTEX
+#endif // C++20
#endif // _GLIBCXX_SEMAPHORE
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 1:27 ` Jonathan Wakely
@ 2020-11-22 12:29 ` Iain Sandoe
2020-11-22 13:37 ` Jonathan Wakely
2020-11-23 18:30 ` Jonathan Wakely
1 sibling, 1 reply; 35+ messages in thread
From: Iain Sandoe @ 2020-11-22 12:29 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: David Edelsohn, Jonathan Wakely, libstdc++, GCC Patches
thanks for looking at this over the weekend.
Jonathan Wakely via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
> <libstdc++@gcc.gnu.org> wrote:
>> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
>> fixes. And a few c++ failures with similar symptoms. I'm not certain
>> that it is due to this patch, but it's the likely suspect.
> Yes, it's that patch.
>
> This should fix most of those errors, but I haven't finished testing
> it, and can't commit it now anyway.
> <patch.txt>
with r11-5235 + this patch there are still quite a few fails on Darwin - but
all seem to be the same ( so maybe only problem ;) ):
“sem_timedwait was not declared in this scope”.
It looks like the semaphore header is optional in SUSv3 (AFAIK that’s still
the claimed edition for Darwin) - and although Darwin has the semaphore
header, it doesn’t seem to have an impl. of sem_timedwait.
just:
int sem_trywait(sem_t *);
int sem_wait(sem_t *) ;
thanks
Iain
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 12:29 ` Iain Sandoe
@ 2020-11-22 13:37 ` Jonathan Wakely
2020-11-23 18:31 ` Jonathan Wakely
0 siblings, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-22 13:37 UTC (permalink / raw)
To: Iain Sandoe; +Cc: David Edelsohn, Jonathan Wakely, libstdc++, GCC Patches
On Sun, 22 Nov 2020, 12:29 Iain Sandoe, <idsandoe@googlemail.com> wrote:
> thanks for looking at this over the weekend.
>
> Jonathan Wakely via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>
> > On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
> > <libstdc++@gcc.gnu.org> wrote:
> >> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
> >> fixes. And a few c++ failures with similar symptoms. I'm not certain
> >> that it is due to this patch, but it's the likely suspect.
> > Yes, it's that patch.
> >
> > This should fix most of those errors, but I haven't finished testing
> > it, and can't commit it now anyway.
> > <patch.txt>
>
> with r11-5235 + this patch there are still quite a few fails on Darwin -
> but
> all seem to be the same ( so maybe only problem ;) ):
> “sem_timedwait was not declared in this scope”.
>
> It looks like the semaphore header is optional in SUSv3 (AFAIK that’s still
> the claimed edition for Darwin) - and although Darwin has the semaphore
> header, it doesn’t seem to have an impl. of sem_timedwait.
>
> just:
> int sem_trywait(sem_t *);
> int sem_wait(sem_t *) ;
>
It probably depends on the _POSIX_TIMEOUTS option which MacOS doesn't
support (optional in POSIX 2001, but not 2008).
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 1:27 ` Jonathan Wakely
2020-11-22 12:29 ` Iain Sandoe
@ 2020-11-23 18:30 ` Jonathan Wakely
1 sibling, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:30 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: David Edelsohn, libstdc++, GCC Patches
[-- Attachment #1: Type: text/plain, Size: 598 bytes --]
On 22/11/20 01:27 +0000, Jonathan Wakely via Libstdc++ wrote:
>On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
><libstdc++@gcc.gnu.org> wrote:
>>
>> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
>> fixes. And a few c++ failures with similar symptoms. I'm not certain
>> that it is due to this patch, but it's the likely suspect.
>Yes, it's that patch.
>
>This should fix most of those errors, but I haven't finished testing
>it, and can't commit it now anyway.
I've committed this now.
Tested powerpc64le-linux and (lightly) on powerpc-aix and
sparc-solaris.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 17290 bytes --]
commit 183ae52b226898cc34aa51d4153cf0c006212a8a
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sun Nov 22 01:00:46 2020
libstdc++: make atomic waiting depend on gthreads or futexes
libstdc++-v3/ChangeLog:
* include/bits/atomic_wait.h: Do not define anything unless
gthreads or futexes are available.
* include/bits/atomic_timed_wait.h: Likewise.
* include/bits/semaphore_base.h: Likewise.
* include/std/semaphore: Likewise.
* include/bits/atomic_base.h (atomic_flag::wait)
(atomic_flag::notify_one, atomic_flag::notify_all)
(__atomic_base<I>::wait, __atomic_base<I>::notify_one)
(__atomic_base<I>::notify_all, __atomic_base<P*>::wait)
(__atomic_base<P*>::notify_one, __atomic_base<P*>::notify_all)
(__atomic_impl::wait, __atomic_impl::notify_one)
(__atomic_impl::notify_all, __atomic_float::wait)
(__atomic_float::notify_one, __atomic_float::notify_all)
(__atomic_ref::wait, __atomic_ref::notify_one)
(__atomic_ref::notify_all): Only define if gthreads or futexes
are available.
* include/std/atomic (atomic::wait, atomic::notify_one)
(atomic::notify_all): Likewise.
* include/std/version (__cpp_lib_semaphore): Define
conditionally.
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 7de02f169977..d7db8612889e 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -230,6 +230,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(bool __old,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -252,6 +253,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(&_M_i, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++20
_GLIBCXX_ALWAYS_INLINE void
@@ -603,6 +605,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(__int_type __old,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -625,6 +628,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(&_M_i, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
_GLIBCXX_ALWAYS_INLINE __int_type
@@ -897,6 +901,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(__pointer_type __old,
memory_order __m = memory_order_seq_cst) noexcept
@@ -919,6 +924,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(&_M_p, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
_GLIBCXX_ALWAYS_INLINE __pointer_type
@@ -1010,6 +1016,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE void
wait(const _Tp* __ptr, _Val<_Tp> __old,
@@ -1034,6 +1041,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::__atomic_notify(__ptr, true); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
template<typename _Tp>
@@ -1289,6 +1297,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(&_M_fp, __old, __m); }
@@ -1306,6 +1315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(&_M_fp); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
value_type
fetch_add(value_type __i,
@@ -1444,6 +1454,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1461,6 +1472,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
private:
_Tp* _M_ptr;
@@ -1557,6 +1569,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1574,6 +1587,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
value_type
fetch_add(value_type __i,
@@ -1730,6 +1744,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1747,6 +1762,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
value_type
fetch_add(value_type __i,
@@ -1857,6 +1873,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{ __atomic_impl::wait(_M_ptr, __old, __m); }
@@ -1874,6 +1891,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __atomic_impl::notify_all(_M_ptr); }
// TODO add const volatile overload
+#endif // GTHREADS || LINUX_FUTEX
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 405f7e93ca85..b13f8aa12861 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -33,6 +33,7 @@
#pragma GCC system_header
#include <bits/c++config.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/functional_hash.h>
#include <bits/atomic_wait.h>
@@ -286,4 +287,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // _GLIBCXX_ATOMIC_TIMED_WAIT_H
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 7b2682a577ef..a40cff124d7d 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -33,6 +33,7 @@
#pragma GCC system_header
#include <bits/c++config.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/functional_hash.h>
#include <bits/gthr.h>
#include <bits/std_mutex.h>
@@ -106,7 +107,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
- template<typename _Tp>
+ template<typename _Tp>
void
__platform_notify(const _Tp* __addr, bool __all) noexcept
{
@@ -175,11 +176,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
bool
_M_waiting() const noexcept
- {
- __platform_wait_t __res;
- __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
- return __res;
- }
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
void
_M_notify(bool __all) noexcept
@@ -305,4 +306,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // _GLIBCXX_ATOMIC_WAIT_H
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index 78a0b6ba26e6..5e29d3783fe1 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -33,6 +33,7 @@
#pragma GCC system_header
#include <bits/c++config.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/atomic_base.h>
#include <bits/atomic_timed_wait.h>
@@ -161,30 +162,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept
{ return _M_try_acquire_until(__clock_t::now() + __rtime); }
- private:
- sem_t _M_semaphore;
- };
+ private:
+ sem_t _M_semaphore;
+ };
#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
- template<typename _Tp>
- struct __atomic_semaphore
+ template<typename _Tp>
+ struct __atomic_semaphore
+ {
+ static_assert(std::is_integral_v<_Tp>);
+ static_assert(__gnu_cxx::__int_traits<_Tp>::__max
+ <= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+ explicit __atomic_semaphore(_Tp __count) noexcept
+ : _M_counter(__count)
{
- static_assert(std::is_integral_v<_Tp>);
- static_assert(__gnu_cxx::__int_traits<_Tp>::__max
- <= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
- static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+ __glibcxx_assert(__count >= 0 && __count <= _S_max);
+ }
- explicit __atomic_semaphore(_Tp __count) noexcept
- : _M_counter(__count)
- {
- __glibcxx_assert(__count >= 0 && __count <= _S_max);
- }
+ __atomic_semaphore(const __atomic_semaphore&) = delete;
+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
- __atomic_semaphore(const __atomic_semaphore&) = delete;
- __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_counter,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+ std::__atomic_wait(&_M_counter, __old, __pred);
+ }
- _GLIBCXX_ALWAYS_INLINE void
- _M_acquire() noexcept
+ bool
+ _M_try_acquire() noexcept
+ {
+ auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
+ auto const __pred = [this, __old]
+ {
+ if (__old == 0)
+ return false;
+
+ auto __prev = __old;
+ return __atomic_impl::compare_exchange_weak(&this->_M_counter,
+ __prev, __prev - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ return std::__atomic_spin(__pred);
+ }
+
+ template<typename _Clock, typename _Duration>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_until(const chrono::time_point<_Clock,
+ _Duration>& __atime) noexcept
{
auto const __pred = [this]
{
@@ -193,51 +232,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__old == 0)
return false;
return __atomic_impl::compare_exchange_strong(&this->_M_counter,
- __old, __old - 1,
- memory_order::acquire,
- memory_order::release);
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
};
+
auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
- std::__atomic_wait(&_M_counter, __old, __pred);
- }
-
- bool
- _M_try_acquire() noexcept
- {
- auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
- auto const __pred = [this, __old]
- {
- if (__old == 0)
- return false;
-
- auto __prev = __old;
- return __atomic_impl::compare_exchange_weak(&this->_M_counter,
- __prev, __prev - 1,
- memory_order::acquire,
- memory_order::release);
- };
- return std::__atomic_spin(__pred);
- }
-
- template<typename _Clock, typename _Duration>
- _GLIBCXX_ALWAYS_INLINE bool
- _M_try_acquire_until(const chrono::time_point<_Clock,
- _Duration>& __atime) noexcept
- {
- auto const __pred = [this]
- {
- auto __old = __atomic_impl::load(&this->_M_counter,
- memory_order::acquire);
- if (__old == 0)
- return false;
- return __atomic_impl::compare_exchange_strong(&this->_M_counter,
- __old, __old - 1,
- memory_order::acquire,
- memory_order::release);
- };
-
- auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
- return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
+ return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
}
template<typename _Rep, typename _Period>
@@ -299,4 +300,5 @@ template<ptrdiff_t __least_max_value>
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // _GLIBCXX_SEMAPHORE_BASE_H
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 5afe33b41d9b..fe4de244f858 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -165,6 +165,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
void wait(bool __old, memory_order __m = memory_order_seq_cst) const
noexcept
{ _M_base.wait(__old, __m); }
@@ -176,6 +177,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void notify_all() const noexcept
{ _M_base.notify_all(); }
+#endif // GTHREADS || LINUX_FUTEX
#endif
};
@@ -379,6 +381,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m)); }
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{
std::__atomic_wait(&_M_i, __old,
@@ -399,7 +402,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void notify_all() const noexcept
{ std::__atomic_notify(&_M_i, true); }
-#endif
+#endif // GTHREADS || LINUX_FUTEX
+#endif // C++20
};
#undef _GLIBCXX20_INIT
@@ -640,6 +644,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
void wait(__pointer_type __old,
memory_order __m = memory_order_seq_cst) noexcept
{ _M_b.wait(__old, __m); }
@@ -651,6 +656,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void notify_all() const noexcept
{ _M_b.notify_all(); }
+#endif // GTHREADS || LINUX_FUTEX
#endif
__pointer_type
fetch_add(ptrdiff_t __d,
@@ -1406,6 +1412,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus > 201703L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
template<typename _Tp>
inline void
atomic_wait(const atomic<_Tp>* __a,
@@ -1429,6 +1436,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
atomic_notify_all(atomic<_Tp>* __a) noexcept
{ __a->notify_all(); }
+#endif // GTHREADS || LINUX_FUTEX
#endif // C++2a
// Function templates for atomic_integral and atomic_pointer operations only.
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
index b4facde4ea1f..f4b83ab6ae3f 100644
--- a/libstdc++-v3/include/std/semaphore
+++ b/libstdc++-v3/include/std/semaphore
@@ -32,14 +32,16 @@
#pragma GCC system_header
#if __cplusplus > 201703L
-#define __cpp_lib_semaphore 201907L
#include <bits/semaphore_base.h>
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <ext/numeric_traits.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+#define __cpp_lib_semaphore 201907L
+
template<ptrdiff_t __least_max_value =
__gnu_cxx::__int_traits<ptrdiff_t>::__max>
class counting_semaphore
@@ -88,5 +90,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using binary_semaphore = std::counting_semaphore<1>;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
-#endif // __cplusplus > 201703L
+#endif // GTHREADS || LINUX_FUTEX
+#endif // C++20
#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 42ed7cb74d38..cf0454dbaf84 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -226,7 +226,9 @@
#if __cpp_lib_concepts
# define __cpp_lib_ranges 201911L
#endif
-#define __cpp_lib_semaphore 201907L
+#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
+# define __cpp_lib_semaphore 201907L
+#endif
#define __cpp_lib_shift 201806L
#if __cpp_lib_concepts
# define __cpp_lib_span 202002L
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 13:37 ` Jonathan Wakely
@ 2020-11-23 18:31 ` Jonathan Wakely
2020-11-23 18:31 ` Jonathan Wakely
2020-11-24 1:48 ` David Edelsohn
0 siblings, 2 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:31 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Iain Sandoe, libstdc++, GCC Patches, David Edelsohn
On 22/11/20 13:37 +0000, Jonathan Wakely via Libstdc++ wrote:
>On Sun, 22 Nov 2020, 12:29 Iain Sandoe, <idsandoe@googlemail.com> wrote:
>
>> thanks for looking at this over the weekend.
>>
>> Jonathan Wakely via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>
>> > On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
>> > <libstdc++@gcc.gnu.org> wrote:
>> >> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
>> >> fixes. And a few c++ failures with similar symptoms. I'm not certain
>> >> that it is due to this patch, but it's the likely suspect.
>> > Yes, it's that patch.
>> >
>> > This should fix most of those errors, but I haven't finished testing
>> > it, and can't commit it now anyway.
>> > <patch.txt>
>>
>> with r11-5235 + this patch there are still quite a few fails on Darwin -
>> but
>> all seem to be the same ( so maybe only problem ;) ):
>> “sem_timedwait was not declared in this scope”.
>>
>> It looks like the semaphore header is optional in SUSv3 (AFAIK that’s still
>> the claimed edition for Darwin) - and although Darwin has the semaphore
>> header, it doesn’t seem to have an impl. of sem_timedwait.
>>
>> just:
>> int sem_trywait(sem_t *);
>> int sem_wait(sem_t *) ;
>>
>
>
>It probably depends on the _POSIX_TIMEOUTS option which MacOS doesn't
>support (optional in POSIX 2001, but not 2008).
Hopefully this fixes it, but I haven't tested it on darwin, only
linux, aix and solaris.
Committed.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-23 18:31 ` Jonathan Wakely
@ 2020-11-23 18:31 ` Jonathan Wakely
2020-11-24 1:48 ` David Edelsohn
1 sibling, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:31 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Iain Sandoe, libstdc++, GCC Patches, David Edelsohn
[-- Attachment #1: Type: text/plain, Size: 1558 bytes --]
On 23/11/20 18:31 +0000, Jonathan Wakely wrote:
>On 22/11/20 13:37 +0000, Jonathan Wakely via Libstdc++ wrote:
>>On Sun, 22 Nov 2020, 12:29 Iain Sandoe, <idsandoe@googlemail.com> wrote:
>>
>>>thanks for looking at this over the weekend.
>>>
>>>Jonathan Wakely via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>
>>>> On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
>>>> <libstdc++@gcc.gnu.org> wrote:
>>>>> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
>>>>> fixes. And a few c++ failures with similar symptoms. I'm not certain
>>>>> that it is due to this patch, but it's the likely suspect.
>>>> Yes, it's that patch.
>>>>
>>>> This should fix most of those errors, but I haven't finished testing
>>>> it, and can't commit it now anyway.
>>>> <patch.txt>
>>>
>>>with r11-5235 + this patch there are still quite a few fails on Darwin -
>>>but
>>>all seem to be the same ( so maybe only problem ;) ):
>>> “sem_timedwait was not declared in this scope”.
>>>
>>>It looks like the semaphore header is optional in SUSv3 (AFAIK that’s still
>>>the claimed edition for Darwin) - and although Darwin has the semaphore
>>>header, it doesn’t seem to have an impl. of sem_timedwait.
>>>
>>>just:
>>>int sem_trywait(sem_t *);
>>>int sem_wait(sem_t *) ;
>>>
>>
>>
>>It probably depends on the _POSIX_TIMEOUTS option which MacOS doesn't
>>support (optional in POSIX 2001, but not 2008).
>
>Hopefully this fixes it, but I haven't tested it on darwin, only
>linux, aix and solaris.
>
>Committed.
With the patch this time ...
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 2736 bytes --]
commit 92b47a321e14f98c524f6e67e7ecabad5afa7886
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Nov 23 17:17:09 2020
libstdc++: Add configure checks for semaphores
This moves the checks for POSIX semaphores to configure time. As well as
requiring <semaphore.h> and SEM_VALUE_MAX, we also require the
sem_timedwait function. That was only optional in POSIX 2001 (and is
absent on Darwin).
libstdc++-v3/ChangeLog:
* acinclude.m4 (GLIBCXX_CHECK_GTHREADS): Check for
* config.h.in: Regenerate.
* configure: Regenerate.
* include/bits/semaphore_base.h (_GLIBCXX_HAVE_POSIX_SEMAPHORE):
Check autoconf macro instead of defining it here.
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 486347b34d94..a4a0bb840181 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -4089,6 +4089,43 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [
fi
fi
+ AC_CHECK_HEADER(semaphore.h, [
+ AC_MSG_CHECKING([for POSIX Semaphores and sem_timedwait])
+ AC_TRY_COMPILE([
+ #include <unistd.h>
+ #include <semaphore.h>
+ #include <limits.h>
+ ],
+ [
+ #if !defined _POSIX_TIMEOUTS || _POSIX_TIMEOUTS <= 0
+ # error "POSIX Timeouts option not supported"
+ #elif !defined _POSIX_SEMAPHORES || _POSIX_SEMAPHORES <= 0
+ # error "POSIX Semaphores option not supported"
+ #else
+ #if defined SEM_VALUE_MAX
+ constexpr int sem_value_max = SEM_VALUE_MAX;
+ #elif defined _POSIX_SEM_VALUE_MAX
+ constexpr int sem_value_max = _POSIX_SEM_VALUE_MAX;
+ #else
+ # error "SEM_VALUE_MAX not available"
+ #endif
+ sem_t sem;
+ sem_init(&sem, 0, sem_value_max);
+ struct timespec ts = { 0 };
+ sem_timedwait(&sem, &ts);
+ #endif
+ ],
+ [ac_have_posix_semaphore=yes],
+ [ac_have_posix_semaphore=no])],
+ [ac_have_posix_semaphore=no])
+
+ if test $ac_have_posix_semaphore = yes ; then
+ AC_DEFINE(_GLIBCXX_HAVE_POSIX_SEMAPHORE,
+ 1,
+ [Define to 1 if POSIX Semaphores with sem_timedwait are available in <semaphore.h>.])
+ fi
+ AC_MSG_RESULT([$ac_have_posix_semaphore])
+
CXXFLAGS="$ac_save_CXXFLAGS"
AC_LANG_RESTORE
])
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index 5e29d3783fe1..0692f95f24f2 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -39,11 +39,9 @@
#include <ext/numeric_traits.h>
-#if __has_include(<semaphore.h>)
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+# include <limits.h>
# include <semaphore.h>
-# if defined SEM_VALUE_MAX || _POSIX_SEM_VALUE_MAX
-# define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
-# endif
#endif
#include <chrono>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-23 18:31 ` Jonathan Wakely
2020-11-23 18:31 ` Jonathan Wakely
@ 2020-11-24 1:48 ` David Edelsohn
1 sibling, 0 replies; 35+ messages in thread
From: David Edelsohn @ 2020-11-24 1:48 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Jonathan Wakely, Iain Sandoe, libstdc++, GCC Patches
On Mon, Nov 23, 2020 at 1:31 PM Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On 22/11/20 13:37 +0000, Jonathan Wakely via Libstdc++ wrote:
> >On Sun, 22 Nov 2020, 12:29 Iain Sandoe, <idsandoe@googlemail.com> wrote:
> >
> >> thanks for looking at this over the weekend.
> >>
> >> Jonathan Wakely via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >>
> >> > On Sat, 21 Nov 2020 at 23:55, David Edelsohn via Libstdc++
> >> > <libstdc++@gcc.gnu.org> wrote:
> >> >> I am seeing 93 new libstdc++ failures on AIX, even after Jonathan's
> >> >> fixes. And a few c++ failures with similar symptoms. I'm not certain
> >> >> that it is due to this patch, but it's the likely suspect.
> >> > Yes, it's that patch.
> >> >
> >> > This should fix most of those errors, but I haven't finished testing
> >> > it, and can't commit it now anyway.
> >> > <patch.txt>
> >>
> >> with r11-5235 + this patch there are still quite a few fails on Darwin -
> >> but
> >> all seem to be the same ( so maybe only problem ;) ):
> >> “sem_timedwait was not declared in this scope”.
> >>
> >> It looks like the semaphore header is optional in SUSv3 (AFAIK that’s still
> >> the claimed edition for Darwin) - and although Darwin has the semaphore
> >> header, it doesn’t seem to have an impl. of sem_timedwait.
> >>
> >> just:
> >> int sem_trywait(sem_t *);
> >> int sem_wait(sem_t *) ;
> >>
> >
> >
> >It probably depends on the _POSIX_TIMEOUTS option which MacOS doesn't
> >support (optional in POSIX 2001, but not 2008).
>
> Hopefully this fixes it, but I haven't tested it on darwin, only
> linux, aix and solaris.
This patch fixed the problems that I saw on AIX. Thanks for addressing it!
Thanks, David
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-25 18:39 ` Jonathan Wakely
@ 2020-11-26 16:26 ` Jonathan Wakely
0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-26 16:26 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 579 bytes --]
On 25/11/20 18:39 +0000, Jonathan Wakely wrote:
>On 25/11/20 10:35 +0000, Jonathan Wakely wrote:
>>I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
>>are still other FAILs to be fixed.
>
>I think the other FAILs are due to a race condition in the tests,
>fixed by this patch. Tested x86_64-linux, powerpc64le-linux,
>sparc-solaris2.11 and powerpc-aix. Committed to trunk.
>
>I'll keep an eye on the testresults to see if this really fixes it or
>not.
This fixes some more races of the same kind, in different tiles.
Tested as above. Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 4212 bytes --]
commit 10522ed1089277e2aa6cd708205aa5c730179cf0
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu Nov 26 12:55:47 2020
libstdc++: Fix some more deadlocks in tests [PR 97936]
The missed notifications fixed in r11-5383 also happen in some other
tests which have similar code.
libstdc++-v3/ChangeLog:
PR libstdc++/97936
* testsuite/29_atomics/atomic/wait_notify/bool.cc: Fix missed
notifications by making the new thread wait until the parent
thread is waiting on the condition variable.
* testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
* testsuite/29_atomics/atomic_ref/wait_notify.cc: Likewise.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index c14a2391d68b..1fc014911737 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -36,11 +36,16 @@ main ()
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
std::atomic<bool> a(false);
std::atomic<bool> b(false);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
a.wait(false);
if (a.load())
@@ -48,7 +53,6 @@ main ()
b.store(true);
}
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(true);
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index 87830236e0ee..3b699e9133b2 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -36,6 +36,7 @@ main ()
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
long aa;
long bb;
@@ -43,12 +44,15 @@ main ()
std::atomic<long*> a(nullptr);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
a.wait(nullptr);
if (a.load() == &aa)
a.store(&bb);
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(&aa);
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 991713fbcdee..5d5e06dde31c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -36,18 +36,22 @@ main()
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
std::atomic_flag a;
std::atomic_flag b;
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
a.wait(false);
b.test_and_set();
b.notify_one();
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.test_and_set();
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
index b38fc206d468..bc5a7d0d8bf9 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -37,17 +37,21 @@ Tp check_wait_notify(Tp val1, Tp val2)
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
Tp aa = val1;
std::atomic_ref<Tp> a(aa);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
a.wait(val1);
if (a.load() != val2)
a = val1;
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(val2);
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-25 10:35 ` Jonathan Wakely
2020-11-25 12:32 ` Jonathan Wakely
@ 2020-11-25 18:39 ` Jonathan Wakely
2020-11-26 16:26 ` Jonathan Wakely
1 sibling, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-25 18:39 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 418 bytes --]
On 25/11/20 10:35 +0000, Jonathan Wakely wrote:
>I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
>are still other FAILs to be fixed.
I think the other FAILs are due to a race condition in the tests,
fixed by this patch. Tested x86_64-linux, powerpc64le-linux,
sparc-solaris2.11 and powerpc-aix. Committed to trunk.
I'll keep an eye on the testresults to see if this really fixes it or
not.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 7093 bytes --]
commit f76cad692a62d44ed32d010200bad74f36c73092
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Nov 25 14:39:54 2020
libstdc++: Fix testsuite helper functions [PR 97936]
This fixes a race condition in the util/atomic/wait_notify_util.h header
used by several tests, which should make the tests work properly.
libstdc++-v3/ChangeLog:
PR libstdc++/97936
* testsuite/29_atomics/atomic/wait_notify/bool.cc: Re-eneable
test.
* testsuite/29_atomics/atomic/wait_notify/generic.cc: Likewise.
* testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
* testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise.
* testsuite/29_atomics/atomic_integral/wait_notify.cc: Likewise.
* testsuite/util/atomic/wait_notify_util.h: Fix missed
notifications by making the new thread wait until the parent
thread is waiting on the condition variable.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index 29781c6e1357..c14a2391d68b 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -2,7 +2,6 @@
// { dg-do run { target c++2a } }
// { dg-require-gthreads "" }
// { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
index 629556a9d2d0..988fe7b334f3 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -2,7 +2,6 @@
// { dg-do run { target c++2a } }
// { dg-require-gthreads "" }
// { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index f54961f893d4..87830236e0ee 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -2,7 +2,6 @@
// { dg-do run { target c++2a } }
// { dg-additional-options "-pthread" { target pthread } }
// { dg-require-gthreads "" }
-// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 763d3e77159c..991713fbcdee 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -2,7 +2,6 @@
// { dg-do run { target c++2a } }
// { dg-require-gthreads "" }
// { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 8f9e4a39a21f..134eff39e1b1 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -3,7 +3,6 @@
// { dg-require-gthreads "" }
// { dg-additional-options "-pthread" { target pthread } }
// { dg-add-options libatomic }
-// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index 762583cf8c76..c65379cba619 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -3,7 +3,6 @@
// { dg-require-gthreads "" }
// { dg-add-options libatomic }
// { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { *-*-* } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
index a319e8b60a69..f5fff4af4e49 100644
--- a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
+++ b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
@@ -34,16 +34,20 @@ Tp check_wait_notify(Tp val1, Tp val2)
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
std::atomic<Tp> a(val1);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
a.wait(val1);
if (a.load() != val2)
a = val1;
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(val2);
@@ -59,10 +63,15 @@ Tp check_wait_notify(Tp val1, Tp val2)
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
std::atomic<Tp> a(val1);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
a.wait(val1);
auto v = a.load();
@@ -70,7 +79,6 @@ Tp check_wait_notify(Tp val1, Tp val2)
if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
a = val1;
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(val2);
@@ -87,16 +95,20 @@ Tp check_atomic_wait_notify(Tp val1, Tp val2)
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
std::atomic<Tp> a(val1);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
std::atomic_wait(&a, val1);
if (a.load() != val2)
a = val1;
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(val2);
@@ -112,10 +124,15 @@ Tp check_atomic_wait_notify(Tp val1, Tp val2)
std::mutex m;
std::condition_variable cv;
+ std::unique_lock<std::mutex> l(m);
std::atomic<Tp> a(val1);
std::thread t([&]
{
+ {
+ // This ensures we block until cv.wait(l) starts.
+ std::lock_guard<std::mutex> ll(m);
+ }
cv.notify_one();
std::atomic_wait(&a, val1);
auto v = a.load();
@@ -123,7 +140,6 @@ Tp check_atomic_wait_notify(Tp val1, Tp val2)
if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
a = val1;
});
- std::unique_lock<std::mutex> l(m);
cv.wait(l);
std::this_thread::sleep_for(100ms);
a.store(val2);
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-25 10:35 ` Jonathan Wakely
@ 2020-11-25 12:32 ` Jonathan Wakely
2020-11-25 18:39 ` Jonathan Wakely
1 sibling, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-25 12:32 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 5109 bytes --]
On 25/11/20 10:35 +0000, Jonathan Wakely wrote:
>On 25/11/20 01:07 +0000, Jonathan Wakely wrote:
>>On 24/11/20 23:45 +0000, Jonathan Wakely wrote:
>>>On 21/11/20 16:36 -0800, H.J. Lu wrote:
>>>>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
>>>><gcc-patches@gcc.gnu.org> wrote:
>>>>>
>>>>>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>>>>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>>>>>
>>>>>>I'm testing this.
>>>>>
>>>>>I'm committing this instead, it's the same but also disables
>>>>>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>>>>
>>>>>Tested sparc-solaris2.11 and powerpc64le-linux.
>>>>>
>>>>>There are still some timeouts on linux:
>>>>>
>>>>>FAIL: 30_threads/latch/3.cc execution test
>>>>>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>>>>
>>>>
>>>>I opened:
>>>>
>>>>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
>>>
>>>I've disabled the failing tests for now. They can be re-enabled after
>>>the problem is found and fixed.
>>
>>I was finally able to reproduce the hangs, and I think this is the
>>fix:
>>
>>--- a/libstdc++-v3/include/bits/atomic_wait.h
>>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>>@@ -100,9 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
>> static_cast<int>(__futex_wait_flags::__wait_private),
>> __val, nullptr);
>>- if (!__e)
>>+ if (!__e || errno == EAGAIN)
>> break;
>>- else if (!(errno == EINTR || errno == EAGAIN))
>>+ else if (errno != EINTR)
>> __throw_system_error(__e);
>> }
>> }
>>
>>The problem is that we're going into a busy loop when SYS_futex
>>returns EAGAIN, but that means the current value doesn't match the
>>expected value, so we should return not keep waiting for the value to
>>change.
>
>I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
>are still other FAILs to be fixed.
Except that what I pushed was not what I wrote above, as noticed by
Jakub. I need to get more sleep.
Fixed with this patch, pushed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1235 bytes --]
commit a5ccfd04605d940daded7e95474389f1c7dfad61
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Nov 25 12:16:07 2020
libstdc++: Fix silly typos [PR 97936]
libstdc++-v3/ChangeLog:
PR libstdc++/97936
* include/bits/atomic_wait.h (__platform_wait): Check errno,
not just the value of EAGAIN.
(__waiters::__waiters()): Fix name of data member.
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index fdf7c4586f22..5af9367ca2e9 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -100,7 +100,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
static_cast<int>(__futex_wait_flags::__wait_private),
__val, nullptr);
- if (!__e || EAGAIN)
+ if (!__e || errno == EAGAIN)
break;
else if (errno != EINTR)
__throw_system_error(__e);
@@ -133,7 +133,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
mutable __gthread_cond_t _M_cv;
__waiters() noexcept
{
- __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cv);
}
# endif
#endif
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-25 1:07 ` Jonathan Wakely
@ 2020-11-25 10:35 ` Jonathan Wakely
2020-11-25 12:32 ` Jonathan Wakely
2020-11-25 18:39 ` Jonathan Wakely
0 siblings, 2 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-25 10:35 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
On 25/11/20 01:07 +0000, Jonathan Wakely wrote:
>On 24/11/20 23:45 +0000, Jonathan Wakely wrote:
>>On 21/11/20 16:36 -0800, H.J. Lu wrote:
>>>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
>>><gcc-patches@gcc.gnu.org> wrote:
>>>>
>>>>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>>>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>>>>
>>>>>I'm testing this.
>>>>
>>>>I'm committing this instead, it's the same but also disables
>>>>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>>>
>>>>Tested sparc-solaris2.11 and powerpc64le-linux.
>>>>
>>>>There are still some timeouts on linux:
>>>>
>>>>FAIL: 30_threads/latch/3.cc execution test
>>>>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>>>
>>>
>>>I opened:
>>>
>>>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
>>
>>I've disabled the failing tests for now. They can be re-enabled after
>>the problem is found and fixed.
>
>I was finally able to reproduce the hangs, and I think this is the
>fix:
>
>--- a/libstdc++-v3/include/bits/atomic_wait.h
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>@@ -100,9 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
> static_cast<int>(__futex_wait_flags::__wait_private),
> __val, nullptr);
>- if (!__e)
>+ if (!__e || errno == EAGAIN)
> break;
>- else if (!(errno == EINTR || errno == EAGAIN))
>+ else if (errno != EINTR)
> __throw_system_error(__e);
> }
> }
>
>The problem is that we're going into a busy loop when SYS_futex
>returns EAGAIN, but that means the current value doesn't match the
>expected value, so we should return not keep waiting for the value to
>change.
I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
are still other FAILs to be fixed.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-24 23:45 ` Jonathan Wakely
@ 2020-11-25 1:07 ` Jonathan Wakely
2020-11-25 10:35 ` Jonathan Wakely
0 siblings, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-25 1:07 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
On 24/11/20 23:45 +0000, Jonathan Wakely wrote:
>On 21/11/20 16:36 -0800, H.J. Lu wrote:
>>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
>><gcc-patches@gcc.gnu.org> wrote:
>>>
>>>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>>>
>>>>I'm testing this.
>>>
>>>I'm committing this instead, it's the same but also disables
>>>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>>
>>>Tested sparc-solaris2.11 and powerpc64le-linux.
>>>
>>>There are still some timeouts on linux:
>>>
>>>FAIL: 30_threads/latch/3.cc execution test
>>>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>>
>>
>>I opened:
>>
>>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
>
>I've disabled the failing tests for now. They can be re-enabled after
>the problem is found and fixed.
I was finally able to reproduce the hangs, and I think this is the
fix:
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -100,9 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
static_cast<int>(__futex_wait_flags::__wait_private),
__val, nullptr);
- if (!__e)
+ if (!__e || errno == EAGAIN)
break;
- else if (!(errno == EINTR || errno == EAGAIN))
+ else if (errno != EINTR)
__throw_system_error(__e);
}
}
The problem is that we're going into a busy loop when SYS_futex
returns EAGAIN, but that means the current value doesn't match the
expected value, so we should return not keep waiting for the value to
change.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 0:36 ` H.J. Lu
2020-11-23 14:50 ` Jonathan Wakely
@ 2020-11-24 23:45 ` Jonathan Wakely
2020-11-25 1:07 ` Jonathan Wakely
1 sibling, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-24 23:45 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 3718 bytes --]
On 21/11/20 16:36 -0800, H.J. Lu wrote:
>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
><gcc-patches@gcc.gnu.org> wrote:
>>
>> On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>> >On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>> >
>> >I'm testing this.
>>
>> I'm committing this instead, it's the same but also disables
>> 29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>
>> Tested sparc-solaris2.11 and powerpc64le-linux.
>>
>> There are still some timeouts on linux:
>>
>> FAIL: 30_threads/latch/3.cc execution test
>> FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>
>
>I opened:
>
>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
I've disabled the failing tests for now. They can be re-enabled after
the problem is found and fixed.
Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 3503 bytes --]
commit a3313a2214a6253672ab4fa37a2dcf57fd0f8dce
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Nov 24 23:22:01 2020
libstdc++: Disable failing tests [PR 97936]
These tests are unstable and causing failures due to timeouts. Disable
them until the cause can be found, so that testing doesn't have to wait
for them to timeout.
libstdc++-v3/ChangeLog:
PR libstdc++/97936
PR libstdc++/97944
* testsuite/29_atomics/atomic_integral/wait_notify.cc: Disable.
Do not require pthreads, but add -pthread when appropriate.
* testsuite/30_threads/jthread/95989.cc: Likewise.
* testsuite/30_threads/latch/3.cc: Likewise.
* testsuite/30_threads/semaphore/try_acquire_until.cc: Likewise.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index abf2bfdbee96..762583cf8c76 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -1,8 +1,9 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
// { dg-add-options libatomic }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { *-*-* } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/30_threads/jthread/95989.cc b/libstdc++-v3/testsuite/30_threads/jthread/95989.cc
index c7a9430eee90..a179eab38198 100644
--- a/libstdc++-v3/testsuite/30_threads/jthread/95989.cc
+++ b/libstdc++-v3/testsuite/30_threads/jthread/95989.cc
@@ -20,6 +20,7 @@
// { dg-require-gthreads {} }
// { dg-additional-options "-pthread" { target pthread } }
// { dg-additional-options "-static" { target static } }
+// { dg-skip-if "broken" { *-*-* } }
#include <thread>
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
index 5d08000f4302..6304135a877c 100644
--- a/libstdc++-v3/testsuite/30_threads/latch/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -15,11 +15,12 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
-//
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { *-*-* } }
+
#include <latch>
#include <atomic>
#include <thread>
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
index af7ab7bac395..5e1141425f72 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -15,10 +15,11 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { *-*-* } }
#include <semaphore>
#include <chrono>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 21:13 ` Stephan Bergmann
@ 2020-11-23 18:33 ` Jonathan Wakely
0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:33 UTC (permalink / raw)
To: Stephan Bergmann; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 2583 bytes --]
On 22/11/20 22:13 +0100, Stephan Bergmann wrote:
>On 20/11/2020 23:44, Thomas Rodgers wrote:
>>Tested x86_64-pc-linux-gnu, committed.
>
>Clang complains:
>
>>$ cat test.cc
>>#include <semaphore>
>>
>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++20 -fsyntax-only test.cc
>>In file included from test.cc:1:
>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/semaphore:36:
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/semaphore_base.h:145:22: error: no viable conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::__platform_semaphore::__clock_t' (aka 'const std::chrono::system_clock')
>> const __clock_t __s_entry = __clock_t::now();
>> ^ ~~~~~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::chrono::system_clock &' for 1st argument
>> struct system_clock
>> ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'std::chrono::system_clock &&' for 1st argument
>>1 error generated.
>
>which
>
>>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>>index 78a0b6ba26e..f25c9fdb325 100644
>>--- a/libstdc++-v3/include/bits/semaphore_base.h
>>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>>@@ -142,7 +142,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> else
>> {
>> const typename _Clock::time_point __c_entry = _Clock::now();
>>- const __clock_t __s_entry = __clock_t::now();
>>+ const __clock_t::time_point __s_entry = __clock_t::now();
>> const auto __delta = __atime - __c_entry;
>> const auto __s_atime = __s_entry + __delta;
>> if (_M_try_acquire_until_impl(__s_atime))
>>~
>
>would fix.
I just used 'auto'` instead.
Committed, thanks.
The fact this didn't error with GCC suggests we're missing some tests.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 972 bytes --]
commit 1ccee0fbfa8e528b3671dfbf4dad5b6f67755e4c
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Nov 23 18:16:44 2020
libstdc++: Fix variable declared with wrong type
libstdc++-v3/ChangeLog:
* include/bits/semaphore_base.h
(__platform_semaphore::_M_try_acquire_until): Fix type of
variable.
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index 0692f95f24f2..56333bbbfef7 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -141,7 +141,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else
{
const typename _Clock::time_point __c_entry = _Clock::now();
- const __clock_t __s_entry = __clock_t::now();
+ const auto __s_entry = __clock_t::now();
const auto __delta = __atime - __c_entry;
const auto __s_atime = __s_entry + __delta;
if (_M_try_acquire_until_impl(__s_atime))
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 21:41 ` Stephan Bergmann
@ 2020-11-23 18:32 ` Jonathan Wakely
0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:32 UTC (permalink / raw)
To: Stephan Bergmann; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches List
[-- Attachment #1: Type: text/plain, Size: 809 bytes --]
On 22/11/20 22:41 +0100, Stephan Bergmann wrote:
>On 20/11/2020 23:44, Thomas Rodgers wrote:
>>Tested x86_64-pc-linux-gnu, committed.
>
>...and there are multiple definition complaints from the linker
>because of two missing "include":
>
>>index 7b2682a577e..23ab2018ca8 100644
>>--- a/libstdc++-v3/include/bits/atomic_wait.h
>>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>>@@ -223,7 +223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> { _M_w._M_do_wait(_M_version); }
>> };
>>- void
>>+ inline void
>> __thread_relax() noexcept
>> {
>> #if defined __i386__ || defined __x86_64__
>>@@ -233,7 +233,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> #endif
>> }
>>- void
>>+ inline void
>> __thread_yield() noexcept
>> {
>> #if defined _GLIBCXX_USE_SCHED_YIELD
Committed, thanks.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 986 bytes --]
commit 0986d3bc621b12c3d0367bf7bd25927c7fbfc552
Author: Stephan Bergmann <sbergman@redhat.com>
Date: Mon Nov 23 18:14:44 2020
libstdc++: Fix linker errors due to missing 'inline' keywords
libstdc++-v3/ChangeLog:
* include/bits/atomic_wait.h (__thread_relax, __thread_yield):
Add 'inline'.
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index a40cff124d7d..cd756f68de6d 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ _M_w._M_do_wait(_M_version); }
};
- void
+ inline void
__thread_relax() noexcept
{
#if defined __i386__ || defined __x86_64__
@@ -234,9 +234,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
}
- void
+ inline void
__thread_yield() noexcept
- {
+ {
#if defined _GLIBCXX_USE_SCHED_YIELD
__gthread_yield();
#endif
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-21 17:39 ` Jonathan Wakely
2020-11-22 0:36 ` H.J. Lu
@ 2020-11-23 16:08 ` Jonathan Wakely
1 sibling, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 16:08 UTC (permalink / raw)
To: Andreas Schwab; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 3424 bytes --]
On 21/11/20 17:39 +0000, Jonathan Wakely wrote:
>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>
>>I'm testing this.
>
>I'm committing this instead, it's the same but also disables
>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>
>Tested sparc-solaris2.11 and powerpc64le-linux.
>
>There are still some timeouts on linux:
>
>FAIL: 30_threads/latch/3.cc execution test
>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
Here's another small fix.
Tested powerpc64le-linux, pushed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 2174 bytes --]
commit fd62daea40e09c1e6d599a6171db6b298d6c362e
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Nov 23 15:46:24 2020
libstdc++: Link tests to libatomic as required [PR 97948]
libstdc++-v3/ChangeLog:
PR libstdc++/97948
* testsuite/29_atomics/atomic_float/wait_notify.cc: Add options
for libatomic.
* testsuite/29_atomics/atomic_integral/wait_notify.cc: Likewise.
* testsuite/29_atomics/atomic_ref/wait_notify.cc: Likewise.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 27d9b601c2f4..8f9e4a39a21f 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -2,6 +2,7 @@
// { dg-do run { target c++2a } }
// { dg-require-gthreads "" }
// { dg-additional-options "-pthread" { target pthread } }
+// { dg-add-options libatomic }
// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index 6e9ee7dbf93f..abf2bfdbee96 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -2,6 +2,7 @@
// { dg-do run { target c++2a } }
// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-add-options libatomic }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
index dc5ae7a21eac..b38fc206d468 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -2,6 +2,7 @@
// { dg-do run { target c++2a } }
// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-add-options libatomic }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-22 0:36 ` H.J. Lu
@ 2020-11-23 14:50 ` Jonathan Wakely
2020-11-24 23:45 ` Jonathan Wakely
1 sibling, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-23 14:50 UTC (permalink / raw)
To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
On 21/11/20 16:36 -0800, H.J. Lu wrote:
>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
><gcc-patches@gcc.gnu.org> wrote:
>>
>> On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>> >On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>> >
>> >I'm testing this.
>>
>> I'm committing this instead, it's the same but also disables
>> 29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>
>> Tested sparc-solaris2.11 and powerpc64le-linux.
>>
>> There are still some timeouts on linux:
>>
>> FAIL: 30_threads/latch/3.cc execution test
>> FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>
>
>I opened:
>
>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
Thanks.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-20 22:44 ` Thomas Rodgers
2020-11-22 21:13 ` Stephan Bergmann
@ 2020-11-22 21:41 ` Stephan Bergmann
2020-11-23 18:32 ` Jonathan Wakely
1 sibling, 1 reply; 35+ messages in thread
From: Stephan Bergmann @ 2020-11-22 21:41 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: trodgers, libstdc++, gcc-patches List, Jonathan Wakely
On 20/11/2020 23:44, Thomas Rodgers wrote:
> Tested x86_64-pc-linux-gnu, committed.
...and there are multiple definition complaints from the linker because
of two missing "include":
> index 7b2682a577e..23ab2018ca8 100644
> --- a/libstdc++-v3/include/bits/atomic_wait.h
> +++ b/libstdc++-v3/include/bits/atomic_wait.h
> @@ -223,7 +223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> { _M_w._M_do_wait(_M_version); }
> };
>
> - void
> + inline void
> __thread_relax() noexcept
> {
> #if defined __i386__ || defined __x86_64__
> @@ -233,7 +233,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> #endif
> }
>
> - void
> + inline void
> __thread_yield() noexcept
> {
> #if defined _GLIBCXX_USE_SCHED_YIELD
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-20 22:44 ` Thomas Rodgers
@ 2020-11-22 21:13 ` Stephan Bergmann
2020-11-23 18:33 ` Jonathan Wakely
2020-11-22 21:41 ` Stephan Bergmann
1 sibling, 1 reply; 35+ messages in thread
From: Stephan Bergmann @ 2020-11-22 21:13 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: trodgers, libstdc++, gcc-patches List, Jonathan Wakely
On 20/11/2020 23:44, Thomas Rodgers wrote:
> Tested x86_64-pc-linux-gnu, committed.
Clang complains:
> $ cat test.cc
> #include <semaphore>
>
> $ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++20 -fsyntax-only test.cc
> In file included from test.cc:1:
> In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/semaphore:36:
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/semaphore_base.h:145:22: error: no viable conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::__platform_semaphore::__clock_t' (aka 'const std::chrono::system_clock')
> const __clock_t __s_entry = __clock_t::now();
> ^ ~~~~~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::chrono::system_clock &' for 1st argument
> struct system_clock
> ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'std::chrono::system_clock &&' for 1st argument
> 1 error generated.
which
> diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
> index 78a0b6ba26e..f25c9fdb325 100644
> --- a/libstdc++-v3/include/bits/semaphore_base.h
> +++ b/libstdc++-v3/include/bits/semaphore_base.h
> @@ -142,7 +142,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> else
> {
> const typename _Clock::time_point __c_entry = _Clock::now();
> - const __clock_t __s_entry = __clock_t::now();
> + const __clock_t::time_point __s_entry = __clock_t::now();
> const auto __delta = __atime - __c_entry;
> const auto __s_atime = __s_entry + __delta;
> if (_M_try_acquire_until_impl(__s_atime))
> ~
would fix.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-21 17:39 ` Jonathan Wakely
@ 2020-11-22 0:36 ` H.J. Lu
2020-11-23 14:50 ` Jonathan Wakely
2020-11-24 23:45 ` Jonathan Wakely
2020-11-23 16:08 ` Jonathan Wakely
1 sibling, 2 replies; 35+ messages in thread
From: H.J. Lu @ 2020-11-22 0:36 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++
On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
> >On 21/11/20 16:16 +0100, Andreas Schwab wrote:
> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> >> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> >> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
> >
> >I'm testing this.
>
> I'm committing this instead, it's the same but also disables
> 29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>
> Tested sparc-solaris2.11 and powerpc64le-linux.
>
> There are still some timeouts on linux:
>
> FAIL: 30_threads/latch/3.cc execution test
> FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>
I opened:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
--
H.J.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-21 17:04 ` Jonathan Wakely
@ 2020-11-21 17:39 ` Jonathan Wakely
2020-11-22 0:36 ` H.J. Lu
2020-11-23 16:08 ` Jonathan Wakely
0 siblings, 2 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-21 17:39 UTC (permalink / raw)
To: Andreas Schwab; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 3281 bytes --]
On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>
>I'm testing this.
I'm committing this instead, it's the same but also disables
29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
Tested sparc-solaris2.11 and powerpc64le-linux.
There are still some timeouts on linux:
FAIL: 30_threads/latch/3.cc execution test
FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 7354 bytes --]
commit 6f5387b7c9047baa5ee1385c8f5148d2c351bd20
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sat Nov 21 16:52:22 2020
libstdc++: Fix atomic waiting for non-linux targets
This fixes some UNRESOLVED tests on (at least) Solaris and Darwin, and
disables some tests that hang forever on Solaris. A proper fix is still
needed.
libstdc++-v3/ChangeLog:
* include/bits/atomic_base.h (atomic_flag::wait): Use correct
type for __atomic_wait call.
* include/bits/atomic_timed_wait.h (__atomic_wait_until): Check
_GLIBCXX_HAVE_LINUX_FUTEX.
* include/bits/atomic_wait.h (__atomic_notify): Likewise.
* include/bits/semaphore_base.h (_GLIBCXX_HAVE_POSIX_SEMAPHORE):
Only define if SEM_VALUE_MAX or _POSIX_SEM_VALUE_MAX is defined.
* testsuite/29_atomics/atomic/wait_notify/bool.cc: Disable on
non-linux targes.
* testsuite/29_atomics/atomic/wait_notify/generic.cc: Likewise.
* testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
* testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise.
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index dd4db926592e..7de02f169977 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -234,7 +234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
wait(bool __old,
memory_order __m = memory_order_seq_cst) const noexcept
{
- std::__atomic_wait(&_M_i, __old,
+ std::__atomic_wait(&_M_i, static_cast<__atomic_flag_data_type>(__old),
[__m, this, __old]()
{ return this->test(__m) != __old; });
}
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 7712a6c591dc..405f7e93ca85 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -240,12 +240,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
do
{
__atomic_wait_status __res;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
if constexpr (__platform_wait_uses_type<_Tp>)
{
__res = __detail::__platform_wait_until((__platform_wait_t*)(void*) __addr,
__old, __atime);
}
else
+#endif
{
__res = __w._M_do_wait_until(__version, __atime);
}
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 2d08e5325fb2..7b2682a577ef 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -292,11 +292,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (!__w._M_waiting())
return;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
if constexpr (__platform_wait_uses_type<_Tp>)
{
__platform_notify((__platform_wait_t*)(void*) __addr, __all);
}
else
+#endif
{
__w._M_notify(__all);
}
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index da6dc4b91858..78a0b6ba26e6 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -39,8 +39,10 @@
#include <ext/numeric_traits.h>
#if __has_include(<semaphore.h>)
-#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
-#include <semaphore.h>
+# include <semaphore.h>
+# if defined SEM_VALUE_MAX || _POSIX_SEM_VALUE_MAX
+# define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+# endif
#endif
#include <chrono>
@@ -54,7 +56,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __platform_semaphore
{
using __clock_t = chrono::system_clock;
+#ifdef SEM_VALUE_MAX
static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+#else
+ static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
+#endif
explicit __platform_semaphore(ptrdiff_t __count) noexcept
{
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index 5f1e30a710fe..29781c6e1357 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
index 0249341055cc..629556a9d2d0 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index 8531bb2e7880..f54961f893d4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
+// { dg-additional-options "-pthread" { target pthread } }
// { dg-require-gthreads "" }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 4f026e1dc9c1..763d3e77159c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 640a84e0342e..27d9b601c2f4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-11-21 15:16 ` Andreas Schwab
@ 2020-11-21 17:04 ` Jonathan Wakely
2020-11-21 17:39 ` Jonathan Wakely
0 siblings, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-11-21 17:04 UTC (permalink / raw)
To: Andreas Schwab; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2902 bytes --]
On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
I'm testing this.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 6587 bytes --]
commit 613ac97bed57eb0edb1803b66d5ce3510e665b3d
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sat Nov 21 16:52:22 2020
libstdc++: Fix atomic waiting for non-linux targets
This fixes some UNRESOLVED tests on (at least) Solaris and Darwin, and
disables some tests that hang forever on Solaris. A proper fix is still
needed.
libstdc++-v3/ChangeLog:
* include/bits/atomic_base.h (atomic_flag::wait): Use correct
type for __atomic_wait call.
* include/bits/atomic_timed_wait.h (__atomic_wait_until): Check
_GLIBCXX_HAVE_LINUX_FUTEX.
* include/bits/atomic_wait.h (__atomic_notify): Likewise.
* include/bits/semaphore_base.h (_GLIBCXX_HAVE_POSIX_SEMAPHORE):
Only define if SEM_VALUE_MAX or _POSIX_SEM_VALUE_MAX is defined.
* testsuite/29_atomics/atomic/wait_notify/bool.cc: Disable on
non-linux targes.
* testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
* testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise.
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index dd4db926592e..7de02f169977 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -234,7 +234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
wait(bool __old,
memory_order __m = memory_order_seq_cst) const noexcept
{
- std::__atomic_wait(&_M_i, __old,
+ std::__atomic_wait(&_M_i, static_cast<__atomic_flag_data_type>(__old),
[__m, this, __old]()
{ return this->test(__m) != __old; });
}
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 7712a6c591dc..405f7e93ca85 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -240,12 +240,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
do
{
__atomic_wait_status __res;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
if constexpr (__platform_wait_uses_type<_Tp>)
{
__res = __detail::__platform_wait_until((__platform_wait_t*)(void*) __addr,
__old, __atime);
}
else
+#endif
{
__res = __w._M_do_wait_until(__version, __atime);
}
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 2d08e5325fb2..7b2682a577ef 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -292,11 +292,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (!__w._M_waiting())
return;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
if constexpr (__platform_wait_uses_type<_Tp>)
{
__platform_notify((__platform_wait_t*)(void*) __addr, __all);
}
else
+#endif
{
__w._M_notify(__all);
}
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index da6dc4b91858..78a0b6ba26e6 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -39,8 +39,10 @@
#include <ext/numeric_traits.h>
#if __has_include(<semaphore.h>)
-#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
-#include <semaphore.h>
+# include <semaphore.h>
+# if defined SEM_VALUE_MAX || _POSIX_SEM_VALUE_MAX
+# define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+# endif
#endif
#include <chrono>
@@ -54,7 +56,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __platform_semaphore
{
using __clock_t = chrono::system_clock;
+#ifdef SEM_VALUE_MAX
static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+#else
+ static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
+#endif
explicit __platform_semaphore(ptrdiff_t __count) noexcept
{
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index 5f1e30a710fe..29781c6e1357 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index 8531bb2e7880..f54961f893d4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
+// { dg-additional-options "-pthread" { target pthread } }
// { dg-require-gthreads "" }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 4f026e1dc9c1..763d3e77159c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 640a84e0342e..27d9b601c2f4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-10-26 21:48 ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
2020-10-27 10:23 ` Jonathan Wakely
@ 2020-11-21 15:16 ` Andreas Schwab
2020-11-21 17:04 ` Jonathan Wakely
1 sibling, 1 reply; 35+ messages in thread
From: Andreas Schwab @ 2020-11-21 15:16 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers
In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: template argument deduction/substitution failed:
In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note: deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
"And now for something completely different."
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-10-27 10:23 ` Jonathan Wakely
@ 2020-11-20 22:44 ` Thomas Rodgers
2020-11-22 21:13 ` Stephan Bergmann
2020-11-22 21:41 ` Stephan Bergmann
0 siblings, 2 replies; 35+ messages in thread
From: Thomas Rodgers @ 2020-11-20 22:44 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-patches List, libstdc++, trodgers
Tested x86_64-pc-linux-gnu, committed.
> On Oct 27, 2020, at 3:23 AM, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On 26/10/20 14:48 -0700, Thomas Rodgers wrote:
>> +#include <ext/numeric_traits.h>
>> +
>> +#if __has_include(<semaphore.h>)
>> +#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>> +#include <semaphore.h>
>
> It occurs to me now that this check probably isn't robust enough. For
> any POSIX system it's probably safe to assume that <semaphore.h> means
> the POSIX header and so sem_t is available.
>
> But on non-POSIX systems there could be some other, unrelated header
> called <semaphore.h> in the include paths that the user is compiling
> this header with. It's not inconceivable that the user's own project
> or some third party lib could provide a file called semaphore.h, which
> wouldn't define sem_t, sem_init etc.
>
> It's OK for now, but we should revisit this and add an autoconf check
> for sem_init etc. to check at build time whether we've got POSIX
> semaphores available or not.
>
> Please add a "FIXME: replace this with an autoconf check" comment
> here.
>
> OK for trunk with that change, thanks.
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-10-26 21:48 ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
@ 2020-10-27 10:23 ` Jonathan Wakely
2020-11-20 22:44 ` Thomas Rodgers
2020-11-21 15:16 ` Andreas Schwab
1 sibling, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-10-27 10:23 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers
On 26/10/20 14:48 -0700, Thomas Rodgers wrote:
>+#include <ext/numeric_traits.h>
>+
>+#if __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
It occurs to me now that this check probably isn't robust enough. For
any POSIX system it's probably safe to assume that <semaphore.h> means
the POSIX header and so sem_t is available.
But on non-POSIX systems there could be some other, unrelated header
called <semaphore.h> in the include paths that the user is compiling
this header with. It's not inconceivable that the user's own project
or some third party lib could provide a file called semaphore.h, which
wouldn't define sem_t, sem_init etc.
It's OK for now, but we should revisit this and add an autoconf check
for sem_init etc. to check at build time whether we've got POSIX
semaphores available or not.
Please add a "FIXME: replace this with an autoconf check" comment
here.
OK for trunk with that change, thanks.
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] libstdc++: Add C++2a synchronization support
2020-10-23 10:28 [PATCH] t/trodgers/c2a_synchronization Jonathan Wakely
@ 2020-10-26 21:48 ` Thomas Rodgers
2020-10-27 10:23 ` Jonathan Wakely
2020-11-21 15:16 ` Andreas Schwab
0 siblings, 2 replies; 35+ messages in thread
From: Thomas Rodgers @ 2020-10-26 21:48 UTC (permalink / raw)
To: gcc-patches, libstdc++; +Cc: trodgers
From: Thomas Rodgers <trodgers@redhat.com>
Add support for -
* atomic_flag::wait/notify_one/notify_all
* atomic::wait/notify_one/notify_all
* counting_semaphore
* binary_semaphore
* latch
libstdc++-v3/ChangeLog:
* include/Makefile.am (bits_headers): Add new header.
* include/Makefile.in: Regenerate.
* include/bits/atomic_base.h (__atomic_flag::wait): Define.
(__atomic_flag::notify_one): Likewise.
(__atomic_flag::notify_all): Likewise.
(__atomic_base<_Itp>::wait): Likewise.
(__atomic_base<_Itp>::notify_one): Likewise.
(__atomic_base<_Itp>::notify_all): Likewise.
(__atomic_base<_Ptp*>::wait): Likewise.
(__atomic_base<_Ptp*>::notify_one): Likewise.
(__atomic_base<_Ptp*>::notify_all): Likewise.
(__atomic_impl::wait): Likewise.
(__atomic_impl::notify_one): Likewise.
(__atomic_impl::notify_all): Likewise.
(__atomic_float<_Fp>::wait): Likewise.
(__atomic_float<_Fp>::notify_one): Likewise.
(__atomic_float<_Fp>::notify_all): Likewise.
(__atomic_ref<_Tp>::wait): Likewise.
(__atomic_ref<_Tp>::notify_one): Likewise.
(__atomic_ref<_Tp>::notify_all): Likewise.
(atomic_wait<_Tp>): Likewise.
(atomic_wait_explicit<_Tp>): Likewise.
(atomic_notify_one<_Tp>): Likewise.
(atomic_notify_all<_Tp>): Likewise.
* include/bits/atomic_wait.h: New file.
* include/bits/atomic_timed_wait.h: New file.
* include/bits/semaphore_base.h: New file.
* include/std/atomic (atomic<bool>::wait): Define.
(atomic<bool>::wait_one): Likewise.
(atomic<bool>::wait_all): Likewise.
(atomic<_Tp>::wait): Likewise.
(atomic<_Tp>::wait_one): Likewise.
(atomic<_Tp>::wait_all): Likewise.
(atomic<_Tp*>::wait): Likewise.
(atomic<_Tp*>::wait_one): Likewise.
(atomic<_Tp*>::wait_all): Likewise.
* include/std/latch: New file.
* include/std/semaphore: New file.
* include/std/version: Add __cpp_lib_semaphore and
__cpp_lib_latch defines.
* testsuite/29_atomic/atomic/wait_notify/bool.cc: New test.
* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
* testsuite/29_atomic/atomic_float/wait_notify.cc: Likewise.
* testsuite/29_atomic/atomic_integral/wait_notify.cc: Likewise.
* testsuite/29_atomic/atomic_ref/wait_notify.cc: Likewise.
* testsuite/30_thread/semaphore/1.cc: New test.
* testsuite/30_thread/semaphore/2.cc: Likewise.
* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
* testsuite/30_thread/latch/1.cc: New test.
* testsuite/30_thread/latch/2.cc: New test.
* testsuite/30_thread/latch/3.cc: New test.
* testsuite/util/atomic/wait_notify_util.h: New File.
---
libstdc++-v3/include/Makefile.am | 5 +
libstdc++-v3/include/Makefile.in | 5 +
libstdc++-v3/include/bits/atomic_base.h | 195 ++++++++++-
libstdc++-v3/include/bits/atomic_timed_wait.h | 287 ++++++++++++++++
libstdc++-v3/include/bits/atomic_wait.h | 306 ++++++++++++++++++
libstdc++-v3/include/bits/semaphore_base.h | 296 +++++++++++++++++
libstdc++-v3/include/std/atomic | 78 +++++
libstdc++-v3/include/std/latch | 91 ++++++
libstdc++-v3/include/std/semaphore | 92 ++++++
libstdc++-v3/include/std/version | 2 +
.../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
.../29_atomics/atomic/wait_notify/generic.cc | 31 ++
.../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
.../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
.../29_atomics/atomic_float/wait_notify.cc | 32 ++
.../29_atomics/atomic_integral/wait_notify.cc | 65 ++++
.../29_atomics/atomic_ref/wait_notify.cc | 103 ++++++
libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/3.cc | 69 ++++
.../testsuite/30_threads/semaphore/1.cc | 27 ++
.../testsuite/30_threads/semaphore/2.cc | 27 ++
.../semaphore/least_max_value_neg.cc | 30 ++
.../30_threads/semaphore/try_acquire.cc | 55 ++++
.../30_threads/semaphore/try_acquire_for.cc | 85 +++++
.../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
.../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
.../testsuite/util/atomic/wait_notify_util.h | 160 +++++++++
28 files changed, 2520 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
create mode 100644 libstdc++-v3/include/std/latch
create mode 100644 libstdc++-v3/include/std/semaphore
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
create mode 100644 libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c90ac555e15..382e94322c1 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
${std_srcdir}/iostream \
${std_srcdir}/istream \
${std_srcdir}/iterator \
+ ${std_srcdir}/latch \
${std_srcdir}/limits \
${std_srcdir}/list \
${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
${std_srcdir}/ratio \
${std_srcdir}/regex \
${std_srcdir}/scoped_allocator \
+ ${std_srcdir}/semaphore \
${std_srcdir}/set \
${std_srcdir}/shared_mutex \
${std_srcdir}/span \
@@ -102,6 +104,8 @@ bits_headers = \
${bits_srcdir}/allocator.h \
${bits_srcdir}/atomic_base.h \
${bits_srcdir}/atomic_futex.h \
+ ${bits_srcdir}/atomic_timed_wait.h \
+ ${bits_srcdir}/atomic_wait.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
${bits_srcdir}/basic_string.h \
@@ -177,6 +181,7 @@ bits_headers = \
${bits_srcdir}/regex_compiler.tcc \
${bits_srcdir}/regex_executor.h \
${bits_srcdir}/regex_executor.tcc \
+ ${bits_srcdir}/semaphore_base.h \
${bits_srcdir}/shared_ptr.h \
${bits_srcdir}/shared_ptr_atomic.h \
${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
#include <bits/atomic_lockfree_defines.h>
#include <bits/move.h>
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
#ifndef _GLIBCXX_ALWAYS_INLINE
#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
-
// Base types for atomics.
template<typename _IntTp>
struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_load(&_M_i, &__v, int(__m));
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
}
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(bool __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]()
+ { return this->test(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
#endif // C++20
_GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__int_type __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __int_type
fetch_add(__int_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__m1), int(__m2));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__pointer_type __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(&_M_p, __old,
+ [__m, this, __old]()
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_p, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_p, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__success), int(__failure));
}
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(const _Tp* __ptr, _Val<_Tp> __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(__ptr, __old,
+ [=]() { return load(__ptr, __m) == __old; });
+ }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, false); }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE _Tp
fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(&_M_fp); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(&_M_fp); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
private:
_Tp* _M_ptr;
};
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..7712a6c591d
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,287 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ enum class __atomic_wait_status { no_timeout, timeout };
+
+ namespace __detail
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __platform_wait_clock_t = chrono::steady_clock;
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until_impl(__platform_wait_t* __addr,
+ __platform_wait_t __val,
+ const chrono::time_point<
+ __platform_wait_clock_t, _Duration>&
+ __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())
+ };
+
+ auto __e = syscall (SYS_futex, __addr,
+ static_cast<int>(__futex_wait_flags::
+ __wait_bitset_private),
+ __val, &__rt, nullptr,
+ static_cast<int>(__futex_wait_flags::
+ __bitset_match_any));
+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+ std::terminate();
+ return (__platform_wait_clock_t::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
+
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+ const chrono::time_point<_Clock, _Duration>&
+ __atime)
+ {
+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+ {
+ return __detail::__platform_wait_until_impl(__addr, __val, __atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __platform_wait_clock_t::time_point __s_entry =
+ __platform_wait_clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (__detail::__platform_wait_until_impl(__addr, __val, __s_atime)
+ == __atomic_wait_status::no_timeout)
+ return __atomic_wait_status::no_timeout;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+ }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<mutex>& __lock,
+ 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())
+ };
+
+ pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+ CLOCK_MONOTONIC,
+ &__ts);
+ return (chrono::steady_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
+#endif
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ 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_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+ &__ts);
+ return (chrono::system_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
+
+ // return true if timeout
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ using __clock_t = chrono::steady_clock;
+#else
+ using __clock_t = chrono::system_clock;
+#endif
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+ return __atomic_wait_status::no_timeout;
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+
+ struct __timed_waiters : __waiters
+ {
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ _M_do_wait_until(__platform_wait_t __version,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ return __detail::__platform_wait_until(&_M_ver, __version, __atime);
+#else
+ __platform_wait_t __cur = 0;
+ __waiters::__lock_t __l(_M_mtx);
+ while (__cur <= __version)
+ {
+ if (__detail::__cond_wait_until(&_M_cv, __l, __atime)
+ == __atomic_wait_status::timeout)
+ return __atomic_wait_status::timeout;
+
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+ return __atomic_wait_status::no_timeout;
+#endif
+ }
+
+ static __timed_waiters&
+ _S_timed_for(void* __t)
+ {
+ static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+ return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+ }
+ };
+ } // namespace __detail
+
+ template<typename _Tp, typename _Pred,
+ typename _Clock, typename _Duration>
+ bool
+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::time_point<_Clock, _Duration>&
+ __atime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+ auto __version = __w._M_enter_wait();
+ do
+ {
+ __atomic_wait_status __res;
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __res = __detail::__platform_wait_until((__platform_wait_t*)(void*) __addr,
+ __old, __atime);
+ }
+ else
+ {
+ __res = __w._M_do_wait_until(__version, __atime);
+ }
+ if (__res == __atomic_wait_status::timeout)
+ return false;
+ }
+ while (!__pred() && __atime < _Clock::now());
+ __w._M_leave_wait();
+
+ // if timed out, return false
+ return (_Clock::now() < __atime);
+ }
+
+ template<typename _Tp, typename _Pred,
+ typename _Rep, typename _Period>
+ bool
+ __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ if (!__rtime.count())
+ return false; // no rtime supplied, and spin did not acquire
+
+ using __dur = chrono::steady_clock::duration;
+ auto __reltime = chrono::duration_cast<__dur>(__rtime);
+ if (__reltime < __rtime)
+ ++__reltime;
+
+
+ return __atomic_wait_until(__addr, __old, std::move(__pred),
+ chrono::steady_clock::now() + __reltime);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..2d08e5325fb
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,306 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __detail
+ {
+ using __platform_wait_t = int;
+
+ constexpr auto __atomic_spin_count_1 = 16;
+ constexpr auto __atomic_spin_count_2 = 12;
+
+ inline constexpr
+ auto __platform_wait_max_value =
+ __gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+ template<typename _Tp>
+ inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ = is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+ = false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ enum class __futex_wait_flags : int
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+ __private_flag = 128,
+#else
+ __private_flag = 0,
+#endif
+ __wait = 0,
+ __wake = 1,
+ __wait_bitset = 9,
+ __wake_bitset = 10,
+ __wait_private = __wait | __private_flag,
+ __wake_private = __wake | __private_flag,
+ __wait_bitset_private = __wait_bitset | __private_flag,
+ __wake_bitset_private = __wake_bitset | __private_flag,
+ __bitset_match_any = -1
+ };
+
+ template<typename _Tp>
+ void
+ __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+ {
+ for(;;)
+ {
+ auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wait_private),
+ __val, nullptr);
+ if (!__e)
+ break;
+ else if (!(errno == EINTR || errno == EAGAIN))
+ __throw_system_error(__e);
+ }
+ }
+
+ template<typename _Tp>
+ void
+ __platform_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wake_private),
+ __all ? INT_MAX : 1);
+ }
+#endif
+
+ struct __waiters
+ {
+ alignas(64) __platform_wait_t _M_ver = 0;
+ alignas(64) __platform_wait_t _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __lock_t = std::unique_lock<std::mutex>;
+ mutable __lock_t::mutex_type _M_mtx;
+
+# ifdef __GTHREAD_COND_INIT
+ mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+ __waiters() noexcept = default;
+# else
+ mutable __gthread_cond_t _M_cv;
+ __waiters() noexcept
+ {
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+ }
+# endif
+#endif
+
+ __platform_wait_t
+ _M_enter_wait() noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+ __atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ return __res;
+ }
+
+ void
+ _M_leave_wait() noexcept
+ {
+ __atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ }
+
+ void
+ _M_do_wait(__platform_wait_t __version) noexcept
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_wait(&_M_ver, __version);
+#else
+ __platform_wait_t __cur = 0;
+ while (__cur <= __version)
+ {
+ __waiters::__lock_t __l(_M_mtx);
+ auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+ if (__e)
+ __throw_system_error(__e);
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+#endif
+ }
+
+ bool
+ _M_waiting() const noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
+
+ void
+ _M_notify(bool __all) noexcept
+ {
+ __atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_notify(&_M_ver, __all);
+#else
+ auto __e = __gthread_cond_broadcast(&_M_cv);
+ if (__e)
+ __throw_system_error(__e);
+#endif
+ }
+
+ static __waiters&
+ _S_for(const void* __t)
+ {
+ const unsigned char __mask = 0xf;
+ static __waiters __w[__mask + 1];
+
+ auto __key = _Hash_impl::hash(__t) & __mask;
+ return __w[__key];
+ }
+ };
+
+ struct __waiter
+ {
+ __waiters& _M_w;
+ __platform_wait_t _M_version;
+
+ template<typename _Tp>
+ __waiter(const _Tp* __addr) noexcept
+ : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+ , _M_version(_M_w._M_enter_wait())
+ { }
+
+ ~__waiter()
+ { _M_w._M_leave_wait(); }
+
+ void _M_do_wait() noexcept
+ { _M_w._M_do_wait(_M_version); }
+ };
+
+ void
+ __thread_relax() noexcept
+ {
+#if defined __i386__ || defined __x86_64__
+ __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ void
+ __thread_yield() noexcept
+ {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ } // namespace __detail
+
+ template<typename _Pred>
+ bool
+ __atomic_spin(_Pred& __pred) noexcept
+ {
+ for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+ {
+ if (__pred())
+ return true;
+
+ if (__i < __detail::__atomic_spin_count_2)
+ __detail::__thread_relax();
+ else
+ __detail::__thread_yield();
+ }
+ return false;
+ }
+
+ template<typename _Tp, typename _Pred>
+ void
+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+ {
+ using namespace __detail;
+ if (std::__atomic_spin(__pred))
+ return;
+
+ __waiter __w(__addr);
+ while (!__pred())
+ {
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_wait(__addr, __old);
+ }
+ else
+ {
+ // TODO support timed backoff when this can be moved into the lib
+ __w._M_do_wait();
+ }
+ }
+ }
+
+ template<typename _Tp>
+ void
+ __atomic_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ using namespace __detail;
+ auto& __w = __waiters::_S_for((void*)__addr);
+ if (!__w._M_waiting())
+ return;
+
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+ }
+ else
+ {
+ __w._M_notify(__all);
+ }
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..da6dc4b9185
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,296 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#include <ext/numeric_traits.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ struct __platform_semaphore
+ {
+ using __clock_t = chrono::system_clock;
+ static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+ explicit __platform_semaphore(ptrdiff_t __count) noexcept
+ {
+ sem_init(&_M_semaphore, 0, __count);
+ }
+
+ __platform_semaphore(const __platform_semaphore&) = delete;
+ __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+ ~__platform_semaphore()
+ { sem_destroy(&_M_semaphore); }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ for (;;)
+ {
+ auto __err = sem_wait(&_M_semaphore);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(std::ptrdiff_t __update) noexcept
+ {
+ for(; __update != 0; --__update)
+ {
+ auto __err = sem_post(&_M_semaphore);
+ if (__err)
+ std::terminate();
+ }
+ }
+
+ bool
+ _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime)
+ noexcept
+ {
+
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ struct timespec __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ for (;;)
+ {
+ if (auto __err = sem_timedwait(&_M_semaphore, &__ts))
+ {
+ if (errno == EINTR)
+ continue;
+ else if (errno == ETIMEDOUT || errno == EINVAL)
+ return false;
+ else
+ std::terminate();
+ }
+ else
+ break;
+ }
+ return true;
+ }
+
+ template<typename _Clock, typename _Duration>
+ bool
+ _M_try_acquire_until(const chrono::time_point<_Clock,
+ _Duration>& __atime) noexcept
+ {
+ if constexpr (std::is_same_v<__clock_t, _Clock>)
+ {
+ return _M_try_acquire_until_impl(__atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (_M_try_acquire_until_impl(__s_atime))
+ return true;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ return (_Clock::now() < __atime);
+ }
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
+ noexcept
+ { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+ private:
+ sem_t _M_semaphore;
+ };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+ template<typename _Tp>
+ struct __atomic_semaphore
+ {
+ static_assert(std::is_integral_v<_Tp>);
+ static_assert(__gnu_cxx::__int_traits<_Tp>::__max
+ <= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+ explicit __atomic_semaphore(_Tp __count) noexcept
+ : _M_counter(__count)
+ {
+ __glibcxx_assert(__count >= 0 && __count <= _S_max);
+ }
+
+ __atomic_semaphore(const __atomic_semaphore&) = delete;
+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_counter,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+ std::__atomic_wait(&_M_counter, __old, __pred);
+ }
+
+ bool
+ _M_try_acquire() noexcept
+ {
+ auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
+ auto const __pred = [this, __old]
+ {
+ if (__old == 0)
+ return false;
+
+ auto __prev = __old;
+ return __atomic_impl::compare_exchange_weak(&this->_M_counter,
+ __prev, __prev - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ return std::__atomic_spin(__pred);
+ }
+
+ template<typename _Clock, typename _Duration>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_until(const chrono::time_point<_Clock,
+ _Duration>& __atime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_counter,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+ return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
+ noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_counter,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+ return __atomic_wait_for(&_M_counter, __old, __pred, __rtime);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(ptrdiff_t __update) noexcept
+ {
+ if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
+ return;
+ if (__update > 1)
+ __atomic_impl::notify_all(&_M_counter);
+ else
+ __atomic_impl::notify_one(&_M_counter);
+ }
+
+ private:
+ alignas(__alignof__(_Tp)) _Tp _M_counter;
+ };
+
+// Note: the _GLIBCXX_REQUIRE_POSIX_SEMAPHORE macro can be used to force the
+// use of Posix semaphores (sem_t). Doing so however, alters the ABI.
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+ // Use futex if available and didn't force use of POSIX
+ using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ using __fast_semaphore = __platform_semaphore;
+#else
+ using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+ using __semaphore_impl = conditional_t<
+ (__least_max_value > 1),
+ conditional_t<
+ (__least_max_value <= __fast_semaphore::_S_max),
+ __fast_semaphore,
+ __atomic_semaphore<ptrdiff_t>>,
+ __fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..5afe33b41d9 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
compare_exchange_strong(bool& __i1, bool __i2,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+ void wait(bool __old, memory_order __m = memory_order_seq_cst) const
+ noexcept
+ { _M_base.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_base.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_base.notify_all(); }
+#endif
};
#if __cplusplus <= 201703L
@@ -363,6 +377,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return compare_exchange_strong(__e, __i, __m,
__cmpexch_failure_order(__m)); }
+
+#if __cplusplus > 201703L
+ void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ {
+ const auto __v = this->load(__m);
+ // TODO make this ignore padding bits when we
+ // can do that
+ return __builtin_memcmp(&__old, &__v,
+ sizeof(_Tp)) != 0;
+ });
+ }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ void notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+#endif
+
};
#undef _GLIBCXX20_INIT
@@ -601,6 +639,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ void wait(__pointer_type __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ { _M_b.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_b.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_b.notify_all(); }
+#endif
__pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1404,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order_seq_cst);
}
+
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ inline void
+ atomic_wait(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old) noexcept
+ { __a->wait(__old); }
+
+ template<typename _Tp>
+ inline void
+ atomic_wait_explicit(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old,
+ std::memory_order __m) noexcept
+ { __a->wait(__old, __m); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_one(atomic<_Tp>* __a) noexcept
+ { __a->notify_one(); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_all(atomic<_Tp>* __a) noexcept
+ { __a->notify_all(); }
+
+#endif // C++2a
+
// Function templates for atomic_integral and atomic_pointer operations only.
// Some operations (and, or, xor) are only available for atomic integrals,
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..9d9c880a88b
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,91 @@
+// <latch> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ class latch
+ {
+ public:
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __gnu_cxx::__int_traits<ptrdiff_t>::__max; }
+
+ constexpr explicit latch(ptrdiff_t __expected) noexcept
+ : _M_a(__expected) { }
+
+ ~latch() = default;
+ latch(const latch&) = delete;
+ latch& operator=(const latch&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ count_down(ptrdiff_t __update = 1)
+ {
+ auto const __old = __atomic_impl::fetch_sub(&_M_a,
+ __update, memory_order::release);
+ if (__old == __update)
+ __atomic_impl::notify_all(&_M_a);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE bool
+ try_wait() const noexcept
+ { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait() const noexcept
+ {
+ auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ std::__atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ arrive_and_wait(ptrdiff_t __update = 1) noexcept
+ {
+ count_down(__update);
+ wait();
+ }
+
+ private:
+ alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+ };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..b4facde4ea1
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<ptrdiff_t __least_max_value =
+ __gnu_cxx::__int_traits<ptrdiff_t>::__max>
+ class counting_semaphore
+ {
+ static_assert(__least_max_value >= 0);
+
+ __semaphore_impl<__least_max_value> _M_sem;
+
+ public:
+ explicit counting_semaphore(ptrdiff_t __desired) noexcept
+ : _M_sem(__desired)
+ { }
+
+ ~counting_semaphore() = default;
+
+ counting_semaphore(const counting_semaphore&) = delete;
+ counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __least_max_value; }
+
+ void
+ release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+ { _M_sem._M_release(__update); }
+
+ void
+ acquire() noexcept(noexcept(_M_sem._M_acquire()))
+ { _M_sem._M_acquire(); }
+
+ bool
+ try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+ { return _M_sem._M_try_acquire(); }
+
+ template<typename _Rep, typename _Period>
+ bool
+ try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+ { return _M_sem._M_try_acquire_for(__rtime); }
+
+ template<typename _Clock, typename _Dur>
+ bool
+ try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+ { return _M_sem._M_try_acquire_until(__atime); }
+ };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index ebb50a04d24..dcfbbb9ee54 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,6 +216,7 @@
#ifdef _GLIBCXX_HAS_GTHREADS
# define __cpp_lib_jthread 201911L
#endif
+#define __cpp_lib_latch 201907L
#define __cpp_lib_list_remove_return_type 201806L
#if __cpp_lib_concepts
# define __cpp_lib_make_obj_using_allocator 201811L
@@ -225,6 +226,7 @@
#if __cpp_lib_concepts
# define __cpp_lib_ranges 201911L
#endif
+#define __cpp_lib_semaphore 201907L
#define __cpp_lib_shift 201806L
#define __cpp_lib_span 202002L
#define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..5f1e30a710f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<bool> a(false);
+ std::atomic<bool> b(false);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ if (a.load())
+ {
+ b.store(true);
+ }
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(true);
+ a.notify_one();
+ t.join();
+ VERIFY( b.load() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..0249341055c
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "atomic/wait_notify_util.h"
+
+int
+main ()
+{
+ struct S{ int i; };
+ check<S> check_s{S{0},S{42}};
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ long aa;
+ long bb;
+
+ std::atomic<long*> a(nullptr);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(nullptr);
+ if (a.load() == &aa)
+ a.store(&bb);
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(&aa);
+ a.notify_one();
+ t.join();
+ VERIFY( a.load() == &bb);
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..4f026e1dc9c
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic_flag a;
+ std::atomic_flag b;
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ b.test_and_set();
+ b.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.test_and_set();
+ a.notify_one();
+ b.wait(false);
+ t.join();
+
+ VERIFY( a.test() );
+ VERIFY( b.test() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
new file mode 100644
index 00000000000..b46eb603304
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "atomic/wait_notify_util.h"
+
+int
+main ()
+{
+ check<float> f;
+ check<double> d;
+ check<long double> l;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
new file mode 100644
index 00000000000..6e9ee7dbf93
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "atomic/wait_notify_util.h"
+
+void
+test01()
+{
+ struct S{ int i; };
+ std::atomic<S> s;
+
+ s.wait(S{42});
+}
+
+int
+main ()
+{
+ // check<bool> bb;
+ check<char> ch;
+ check<signed char> sch;
+ check<unsigned char> uch;
+ check<short> s;
+ check<unsigned short> us;
+ check<int> i;
+ check<unsigned int> ui;
+ check<long> l;
+ check<unsigned long> ul;
+ check<long long> ll;
+ check<unsigned long long> ull;
+
+ check<wchar_t> wch;
+ check<char8_t> ch8;
+ check<char16_t> ch16;
+ check<char32_t> ch32;
+
+ check<int8_t> i8;
+ check<int16_t> i16;
+ check<int32_t> i32;
+ check<int64_t> i64;
+
+ check<uint8_t> u8;
+ check<uint16_t> u16;
+ check<uint32_t> u32;
+ check<uint64_t> u64;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ Tp aa = val1;
+ std::atomic_ref<Tp> a(aa);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp,
+ bool = std::is_integral_v<Tp>
+ || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+ check()
+ {
+ Tp a = 0;
+ Tp b = 42;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+ check(Tp b)
+ {
+ Tp a;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+struct foo
+{
+ long a = 0;
+ long b = 0;
+
+ foo& operator=(foo const&) = default;
+
+ friend bool
+ operator==(foo const& rhs, foo const& lhs)
+ { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+ check<long>();
+ check<double>();
+ check<foo>({42, 48});
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..5d08000f430
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,69 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::latch l(3);
+
+ VERIFY( !l.try_wait() );
+
+ auto fn = [&]
+ {
+ l.count_down();
+ };
+
+ std::thread t0(fn);
+ std::thread t1(fn);
+
+ l.arrive_and_wait();
+ t0.join();
+ t1.join();
+
+ VERIFY( l.try_wait() );
+}
+
+void
+test02()
+{
+ std::latch l(3);
+ std::thread t([&]
+ {
+ l.count_down();
+ });
+
+ l.arrive_and_wait(2);
+ t.join();
+ VERIFY( l.try_wait() );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+ std::counting_semaphore<-1> sem(2);
+ return 0;
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::counting_semaphore<10> s(3);
+
+ s.acquire();
+ VERIFY( s.try_acquire() );
+ VERIFY( s.try_acquire() );
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+ std::binary_semaphore s(1);
+
+ s.acquire();
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+void test03()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test04()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s._M_try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s._M_try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ test01();
+ test02();
+ test03();
+ test04();
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s.try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s.try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
@@ -0,0 +1,160 @@
+// 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+ check(Tp a = 0, Tp b = 42)
+ {
+ if constexpr (std::equality_comparable<Tp>)
+ {
+ VERIFY( check_wait_notify(a, b) == b);
+ VERIFY( check_atomic_wait_notify(a, b) == b);
+ }
+ else
+ {
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+ }
+
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_atomic_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+ }
+ }
+ }
+};
--
2.26.2
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] libstdc++: Add C++2a synchronization support
2020-10-01 23:37 ` Thomas Rodgers
@ 2020-10-02 15:40 ` Thomas Rodgers
0 siblings, 0 replies; 35+ messages in thread
From: Thomas Rodgers @ 2020-10-02 15:40 UTC (permalink / raw)
To: gcc-patches, libstdc++; +Cc: trodgers
From: Thomas Rodgers <trodgers@redhat.com>
Updated patch incorporating latest feedback (revised).
Add support for -
* atomic_flag::wait/notify_one/notify_all
* atomic::wait/notify_one/notify_all
* counting_semaphore
* binary_semaphore
* latch
libstdc++-v3/ChangeLog:
* include/Makefile.am (bits_headers): Add new header.
* include/Makefile.in: Regenerate.
* include/bits/atomic_base.h (__atomic_flag::wait): Define.
(__atomic_flag::notify_one): Likewise.
(__atomic_flag::notify_all): Likewise.
(__atomic_base<_Itp>::wait): Likewise.
(__atomic_base<_Itp>::notify_one): Likewise.
(__atomic_base<_Itp>::notify_all): Likewise.
(__atomic_base<_Ptp*>::wait): Likewise.
(__atomic_base<_Ptp*>::notify_one): Likewise.
(__atomic_base<_Ptp*>::notify_all): Likewise.
(__atomic_impl::wait): Likewise.
(__atomic_impl::notify_one): Likewise.
(__atomic_impl::notify_all): Likewise.
(__atomic_float<_Fp>::wait): Likewise.
(__atomic_float<_Fp>::notify_one): Likewise.
(__atomic_float<_Fp>::notify_all): Likewise.
(__atomic_ref<_Tp>::wait): Likewise.
(__atomic_ref<_Tp>::notify_one): Likewise.
(__atomic_ref<_Tp>::notify_all): Likewise.
(atomic_wait<_Tp>): Likewise.
(atomic_wait_explicit<_Tp>): Likewise.
(atomic_notify_one<_Tp>): Likewise.
(atomic_notify_all<_Tp>): Likewise.
* include/bits/atomic_wait.h: New file.
* include/bits/atomic_timed_wait.h: New file.
* include/bits/semaphore_base.h: New file.
* include/std/atomic (atomic<bool>::wait): Define.
(atomic<bool>::wait_one): Likewise.
(atomic<bool>::wait_all): Likewise.
(atomic<_Tp>::wait): Likewise.
(atomic<_Tp>::wait_one): Likewise.
(atomic<_Tp>::wait_all): Likewise.
(atomic<_Tp*>::wait): Likewise.
(atomic<_Tp*>::wait_one): Likewise.
(atomic<_Tp*>::wait_all): Likewise.
* include/std/latch: New file.
* include/std/semaphore: New file.
* include/std/version: Add __cpp_lib_semaphore and
__cpp_lib_latch defines.
* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
* testsuite/30_thread/semaphore/1.cc: New test.
* testsuite/30_thread/semaphore/2.cc: Likewise.
* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
* testsuite/30_thread/latch/1.cc: New test.
* testsuite/30_thread/latch/2.cc: New test.
* testsuite/30_thread/latch/3.cc: New test.
---
libstdc++-v3/include/Makefile.am | 5 +
libstdc++-v3/include/Makefile.in | 5 +
libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
libstdc++-v3/include/std/atomic | 73 +++++
libstdc++-v3/include/std/latch | 90 ++++++
libstdc++-v3/include/std/semaphore | 92 ++++++
libstdc++-v3/include/std/version | 2 +
.../atomic/wait_notify/atomic_refs.cc | 103 ++++++
.../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
.../29_atomics/atomic/wait_notify/floats.cc | 32 ++
.../29_atomics/atomic/wait_notify/generic.cc | 31 ++
.../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
.../atomic/wait_notify/integrals.cc | 65 ++++
.../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
.../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
.../testsuite/30_threads/semaphore/1.cc | 27 ++
.../testsuite/30_threads/semaphore/2.cc | 27 ++
.../semaphore/least_max_value_neg.cc | 30 ++
.../30_threads/semaphore/try_acquire.cc | 55 ++++
.../30_threads/semaphore/try_acquire_for.cc | 85 +++++
.../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
.../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
28 files changed, 2471 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
create mode 100644 libstdc++-v3/include/std/latch
create mode 100644 libstdc++-v3/include/std/semaphore
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
${std_srcdir}/iostream \
${std_srcdir}/istream \
${std_srcdir}/iterator \
+ ${std_srcdir}/latch \
${std_srcdir}/limits \
${std_srcdir}/list \
${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
${std_srcdir}/ratio \
${std_srcdir}/regex \
${std_srcdir}/scoped_allocator \
+ ${std_srcdir}/semaphore \
${std_srcdir}/set \
${std_srcdir}/shared_mutex \
${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
${bits_srcdir}/allocated_ptr.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/atomic_base.h \
+ ${bits_srcdir}/atomic_wait.h \
+ ${bits_srcdir}/atomic_timed_wait.h \
${bits_srcdir}/atomic_futex.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
${bits_srcdir}/regex_compiler.tcc \
${bits_srcdir}/regex_executor.h \
${bits_srcdir}/regex_executor.tcc \
+ ${bits_srcdir}/semaphore_base.h \
${bits_srcdir}/shared_ptr.h \
${bits_srcdir}/shared_ptr_atomic.h \
${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
#include <bits/atomic_lockfree_defines.h>
#include <bits/move.h>
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
#ifndef _GLIBCXX_ALWAYS_INLINE
#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
-
// Base types for atomics.
template<typename _IntTp>
struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_load(&_M_i, &__v, int(__m));
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
}
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(bool __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]()
+ { return this->test(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
#endif // C++20
_GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__int_type __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __int_type
fetch_add(__int_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__m1), int(__m2));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__pointer_type __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(&_M_p, __old,
+ [__m, this, __old]()
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_p, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_p, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__success), int(__failure));
}
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(const _Tp* __ptr, _Val<_Tp> __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(__ptr, __old,
+ [=]() { return load(__ptr, __m) == __old; });
+ }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, false); }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE _Tp
fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(&_M_fp); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(&_M_fp); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
private:
_Tp* _M_ptr;
};
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ enum class __atomic_wait_status { no_timeout, timeout };
+
+ namespace __detail
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __platform_wait_clock_t = chrono::steady_clock;
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until_impl(__platform_wait_t* __addr,
+ __platform_wait_t __val,
+ const chrono::time_point<__platform_wait_clock_t,
+ _Duration>& __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())
+ };
+
+ auto __e = syscall (SYS_futex, __addr,
+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+ __val, &__rt, nullptr,
+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+ std::terminate();
+ return (__platform_wait_clock_t::now() < __atime)
+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+ }
+
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+ {
+ return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __platform_wait_clock_t::time_point __s_entry =
+ __platform_wait_clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
+ __atomic_wait_status::no_timeout)
+ return __atomic_wait_status::no_timeout;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+ }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<mutex>& __lock,
+ 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())
+ };
+
+ pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+ CLOCK_MONOTONIC,
+ &__ts);
+ return (chrono::steady_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+ }
+#endif
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ 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_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+ &__ts);
+ return (chrono::system_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
+
+ // return true if timeout
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ using __clock_t = chrono::steady_clock;
+#else
+ using __clock_t = chrono::system_clock;
+#endif
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+ return __atomic_wait_status::no_timeout;
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+
+ struct __timed_waiters : __waiters
+ {
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ _M_do_wait_until(__platform_wait_t __version,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+ __platform_wait_t __cur = 0;
+ __waiters::__lock_t __l(_M_mtx);
+ while (__cur <= __version)
+ {
+ if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
+ __atomic_wait_status::timeout)
+ return __atomic_wait_status::timeout;
+
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+ return __atomic_wait_status::no_timeout;
+#endif
+ }
+
+ static __timed_waiters&
+ _S_timed_for(void* __t)
+ {
+ static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+ return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+ }
+ };
+ } // namespace __detail
+
+ template<typename _Tp, typename _Pred,
+ typename _Clock, typename _Duration>
+ bool
+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+ auto __version = __w._M_enter_wait();
+ do
+ {
+ __atomic_wait_status __res;
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+ __old,
+ __atime);
+ }
+ else
+ {
+ __res = __w._M_do_wait_until(__version, __atime);
+ }
+ if (__res == __atomic_wait_status::timeout)
+ return false;
+ }
+ while (!__pred() && __atime < _Clock::now());
+ __w._M_leave_wait();
+
+ // if timed out, return false
+ return (_Clock::now() < __atime);
+ }
+
+ template<typename _Tp, typename _Pred,
+ typename _Rep, typename _Period>
+ bool
+ __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ if (!__rtime.count())
+ return false; // no rtime supplied, and spin did not acquire
+
+ using __dur = chrono::steady_clock::duration;
+ auto __reltime = chrono::duration_cast<__dur>(__rtime);
+ if (__reltime < __rtime)
+ ++__reltime;
+
+
+ return __atomic_wait_until(__addr, __old, std::move(__pred),
+ chrono::steady_clock::now() + __reltime);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..21ec3d38c94
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,301 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __detail
+ {
+ using __platform_wait_t = int;
+
+ constexpr auto __atomic_spin_count_1 = 16;
+ constexpr auto __atomic_spin_count_2 = 12;
+
+ inline constexpr
+ auto __platform_wait_max_value =
+ __gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+ template<typename _Tp>
+ inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ = is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+ = false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ enum class __futex_wait_flags : int
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+ __private_flag = 128,
+#else
+ __private_flag = 0,
+#endif
+ __wait = 0,
+ __wake = 1,
+ __wait_bitset = 9,
+ __wake_bitset = 10,
+ __wait_private = __wait | __private_flag,
+ __wake_private = __wake | __private_flag,
+ __wait_bitset_private = __wait_bitset | __private_flag,
+ __wake_bitset_private = __wake_bitset | __private_flag,
+ __bitset_match_any = -1
+ };
+
+ template<typename _Tp>
+ void
+ __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+ {
+ auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wait_private),
+ __val, nullptr);
+ if (__e && !(errno == EINTR || errno == EAGAIN))
+ std::terminate();
+ }
+
+ template<typename _Tp>
+ void
+ __platform_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wake_private),
+ __all ? INT_MAX : 1);
+ }
+#endif
+
+ struct __waiters
+ {
+ __platform_wait_t alignas(64) _M_ver = 0;
+ __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __lock_t = std::unique_lock<std::mutex>;
+ mutable __lock_t::mutex_type _M_mtx;
+
+# ifdef __GTHREAD_COND_INIT
+ mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+ __waiters() noexcept = default;
+# else
+ mutable __gthread_cond_t _M_cv;
+ __waiters() noexcept
+ {
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+ }
+# endif
+#endif
+
+ __platform_wait_t
+ _M_enter_wait() noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+ __atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ return __res;
+ }
+
+ void
+ _M_leave_wait() noexcept
+ {
+ __atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ }
+
+ void
+ _M_do_wait(__platform_wait_t __version) noexcept
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_wait(&_M_ver, __version);
+#else
+ __platform_wait_t __cur = 0;
+ while (__cur <= __version)
+ {
+ __waiters::__lock_t __l(_M_mtx);
+ auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+ if (__e)
+ std::terminate();
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+#endif
+ }
+
+ __platform_wait_t
+ _M_waiting() const noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
+
+ void
+ _M_notify(bool __all) noexcept
+ {
+ __atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_notify(&_M_ver, __all);
+#else
+ auto __e = __gthread_cond_broadcast(&_M_cv);
+ if (__e)
+ __throw_system_error(__e);
+#endif
+ }
+
+ static __waiters&
+ _S_for(const void* __t)
+ {
+ const unsigned char __mask = 0xf;
+ static __waiters __w[__mask + 1];
+
+ auto __key = _Hash_impl::hash(__t) & __mask;
+ return __w[__key];
+ }
+ };
+
+ struct __waiter
+ {
+ __waiters& _M_w;
+ __platform_wait_t _M_version;
+
+ template<typename _Tp>
+ __waiter(const _Tp* __addr) noexcept
+ : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+ , _M_version(_M_w._M_enter_wait())
+ { }
+
+ ~__waiter()
+ { _M_w._M_leave_wait(); }
+
+ void _M_do_wait() noexcept
+ { _M_w._M_do_wait(_M_version); }
+ };
+
+ void
+ __thread_relax() noexcept
+ {
+#if defined __i386__ || defined __x86_64__
+ __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ void
+ __thread_yield() noexcept
+ {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ } // namespace __detail
+
+ template<typename _Pred>
+ bool
+ __atomic_spin(_Pred __pred) noexcept
+ {
+ for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+ {
+ if (__pred())
+ return true;
+
+ if (__i < __detail::__atomic_spin_count_2)
+ __detail::__thread_relax();
+ else
+ __detail::__thread_yield();
+ }
+ return false;
+ }
+
+ template<typename _Tp, typename _Pred>
+ void
+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+ {
+ using namespace __detail;
+ if (__atomic_spin(__pred))
+ return;
+
+ __waiter __w(__addr);
+ while (!__pred())
+ {
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_wait(__addr, __old);
+ }
+ else
+ {
+ // TODO support timed backoff when this can be moved into the lib
+ __w._M_do_wait();
+ }
+ }
+ }
+
+ template<typename _Tp>
+ void
+ __atomic_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ using namespace __detail;
+ auto& __w = __waiters::_S_for((void*)__addr);
+ if (!__w._M_waiting())
+ return;
+
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+ }
+ else
+ {
+ __w._M_notify(__all);
+ }
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..ed127a7a953
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#include <iostream>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ struct __platform_semaphore
+ {
+ using __clock_t = chrono::system_clock;
+ static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+ explicit __platform_semaphore(ptrdiff_t __count) noexcept
+ {
+ sem_init(&_M_semaphore, 0, __count);
+ }
+
+ __platform_semaphore(const __platform_semaphore&) = delete;
+ __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+ ~__platform_semaphore()
+ { sem_destroy(&_M_semaphore); }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ for (;;)
+ {
+ auto __err = sem_wait(&_M_semaphore);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(std::ptrdiff_t __update) noexcept
+ {
+ for(; __update != 0; --__update)
+ {
+ auto __err = sem_post(&_M_semaphore);
+ if (__err)
+ std::terminate();
+ }
+ }
+
+ bool
+ _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
+ {
+
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ struct timespec __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ for (;;)
+ {
+ auto __err = sem_timedwait(&_M_semaphore, &__ts);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err && (errno == ETIMEDOUT))
+ return false;
+ else if (__err && (errno == EINVAL))
+ return false; // caller supplied an invalid __atime
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ return true;
+ }
+
+ template<typename _Clock, typename _Duration>
+ bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ if constexpr (std::is_same<__clock_t, _Clock>::value)
+ {
+ return _M_try_acquire_until_impl(__atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (_M_try_acquire_until_impl(__s_atime))
+ return true;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ return (_Clock::now() < __atime);
+ }
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+ private:
+ sem_t _M_semaphore;
+ };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+ template<typename _Tp>
+ struct __atomic_semaphore
+ {
+ static_assert(std::is_integral_v<_Tp>);
+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+ explicit __atomic_semaphore(_Tp __count) noexcept
+ : _M_a(__count)
+ { }
+
+ __atomic_semaphore(const __atomic_semaphore&) = delete;
+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ __atomic_wait(&_M_a, __old, __pred);
+ }
+
+ bool
+ _M_try_acquire() noexcept
+ {
+ auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ if (__old == 0)
+ return false;
+
+ return __atomic_spin([this, &__old]
+ {
+ return __atomic_impl::compare_exchange_weak(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ });
+ }
+
+ template<typename _Clock, typename _Duration>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ return __atomic_wait_until(&_M_a, __old, __pred, __atime);
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(ptrdiff_t __update) noexcept
+ {
+ if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
+ return;
+ if (__update > 1)
+ __atomic_impl::notify_all(&_M_a);
+ else
+ __atomic_impl::notify_one(&_M_a);
+ }
+
+ private:
+ alignas(__alignof__(_Tp)) _Tp _M_a;
+ };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+ // Use futex if available and didn't force use of POSIX
+ using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ using __fast_semaphore = __platform_semaphore;
+#else
+ using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+ using __semaphore_impl = conditional_t<
+ (__least_max_value > 1),
+ conditional_t<
+ (__least_max_value <= __fast_semaphore::_S_max),
+ __fast_semaphore,
+ __atomic_semaphore<ptrdiff_t>>,
+ __fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..c15909d9ccb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
compare_exchange_strong(bool& __i1, bool __i2,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+ void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { _M_base.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_base.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_base.notify_all(); }
+#endif
};
#if __cplusplus <= 201703L
@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return compare_exchange_strong(__e, __i, __m,
__cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+ void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ {
+ const auto __v = this->load(__m);
+ // TODO make this ignore padding bits when we can do that
+ return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
+ });
+ }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ void notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+#endif
+
};
#undef _GLIBCXX20_INIT
@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+ { _M_b.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_b.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_b.notify_all(); }
+#endif
__pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order_seq_cst);
}
+
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ inline void
+ atomic_wait(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old) noexcept
+ { __a->wait(__old); }
+
+ template<typename _Tp>
+ inline void
+ atomic_wait_explicit(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old,
+ std::memory_order __m) noexcept
+ { __a->wait(__old, __m); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_one(atomic<_Tp>* __a) noexcept
+ { __a->notify_one(); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_all(atomic<_Tp>* __a) noexcept
+ { __a->notify_all(); }
+
+#endif // C++2a
+
// Function templates for atomic_integral and atomic_pointer operations only.
// Some operations (and, or, xor) are only available for atomic integrals,
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..bd06db5aa7f
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,90 @@
+// <latch> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ class latch
+ {
+ public:
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+ constexpr explicit latch(ptrdiff_t __expected) noexcept
+ : _M_a(__expected) { }
+
+ ~latch() = default;
+ latch(const latch&) = delete;
+ latch& operator=(const latch&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ count_down(ptrdiff_t __update = 1)
+ {
+ auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
+ if (__old == __update)
+ __atomic_impl::notify_all(&_M_a);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE bool
+ try_wait() const noexcept
+ { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait() const
+ {
+ auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ arrive_and_wait(ptrdiff_t __update = 1)
+ {
+ count_down();
+ wait();
+ }
+
+ private:
+ alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+ };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..865d6c4aecb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<ptrdiff_t __least_max_value =
+ __gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
+ class counting_semaphore
+ {
+ static_assert(__least_max_value >= 0);
+
+ __semaphore_impl<__least_max_value> _M_sem;
+
+ public:
+ explicit counting_semaphore(ptrdiff_t __desired) noexcept
+ : _M_sem(__desired)
+ { }
+
+ ~counting_semaphore() = default;
+
+ counting_semaphore(const counting_semaphore&) = delete;
+ counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __least_max_value; }
+
+ void
+ release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+ { _M_sem._M_release(__update); }
+
+ void
+ acquire() noexcept(noexcept(_M_sem._M_acquire()))
+ { _M_sem._M_acquire(); }
+
+ bool
+ try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+ { return _M_sem._M_try_acquire(); }
+
+ template<class _Rep, class _Period>
+ bool
+ try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+ { return _M_sem._M_try_acquire_for(__rtime); }
+
+ template<class _Clock, class _Dur>
+ bool
+ try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+ { return _M_sem._M_try_acquire_until(__atime); }
+ };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..b9c7c6c62a8 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,12 +216,14 @@
#ifdef _GLIBCXX_HAS_GTHREADS
# define __cpp_lib_jthread 201911L
#endif
+#define __cpp_lib_latch 201907L
#define __cpp_lib_list_remove_return_type 201806L
#define __cpp_lib_math_constants 201907L
#define __cpp_lib_polymorphic_allocator 201902L
#if __cpp_lib_concepts
# define __cpp_lib_ranges 201911L
#endif
+#define __cpp_lib_semaphore 201907L
#define __cpp_lib_shift 201806L
#define __cpp_lib_span 202002L
#define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ Tp aa = val1;
+ std::atomic_ref<Tp> a(aa);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp,
+ bool = std::is_integral_v<Tp>
+ || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+ check()
+ {
+ Tp a = 0;
+ Tp b = 42;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+ check(Tp b)
+ {
+ Tp a;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+struct foo
+{
+ long a = 0;
+ long b = 0;
+
+ foo& operator=(foo const&) = default;
+
+ friend bool
+ operator==(foo const& rhs, foo const& lhs)
+ { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+ check<long>();
+ check<double>();
+ check<foo>({42, 48});
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..b9fc063c66f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<bool> a(false);
+ std::atomic<bool> b(false);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ if (a.load())
+ {
+ b.store(true);
+ }
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(true);
+ a.notify_one();
+ t.join();
+ VERIFY( b.load() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
new file mode 100644
index 00000000000..1d032085752
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+int
+main ()
+{
+ check<float> f;
+ check<double> d;
+ check<long double> l;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..d15b9c86ae6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+int
+main ()
+{
+ struct S{ int i; };
+ check<S> check_s{S{0},S{42}};
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,160 @@
+// 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+ check(Tp a = 0, Tp b = 42)
+ {
+ if constexpr (std::equality_comparable<Tp>)
+ {
+ VERIFY( check_wait_notify(a, b) == b);
+ VERIFY( check_atomic_wait_notify(a, b) == b);
+ }
+ else
+ {
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+ }
+
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_atomic_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+ }
+ }
+ }
+};
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
new file mode 100644
index 00000000000..115cb79a040
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+void
+test01()
+{
+ struct S{ int i; };
+ std::atomic<S> s;
+
+ s.wait(S{42});
+}
+
+int
+main ()
+{
+ // check<bool> bb;
+ check<char> ch;
+ check<signed char> sch;
+ check<unsigned char> uch;
+ check<short> s;
+ check<unsigned short> us;
+ check<int> i;
+ check<unsigned int> ui;
+ check<long> l;
+ check<unsigned long> ul;
+ check<long long> ll;
+ check<unsigned long long> ull;
+
+ check<wchar_t> wch;
+ check<char8_t> ch8;
+ check<char16_t> ch16;
+ check<char32_t> ch32;
+
+ check<int8_t> i8;
+ check<int16_t> i16;
+ check<int32_t> i32;
+ check<int64_t> i64;
+
+ check<uint8_t> u8;
+ check<uint16_t> u16;
+ check<uint32_t> u32;
+ check<uint64_t> u64;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ long aa;
+ long bb;
+
+ std::atomic<long*> a(nullptr);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(nullptr);
+ if (a.load() == &aa)
+ a.store(&bb);
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(&aa);
+ a.notify_one();
+ t.join();
+ VERIFY( a.load() == &bb);
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..6de7873ecc2
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic_flag a;
+ std::atomic_flag b;
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ b.test_and_set();
+ b.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.test_and_set();
+ a.notify_one();
+ b.wait(false);
+ t.join();
+
+ VERIFY( a.test() );
+ VERIFY( b.test() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+ std::atomic<int> a(0);
+
+ std::latch l(3);
+
+ VERIFY( !l.try_wait() );
+
+ auto fn = [&]
+ {
+ ++a;
+ l.count_down();
+ };
+
+ std::thread t0(fn);
+ std::thread t1(fn);
+
+ l.arrive_and_wait();
+ t0.join();
+ t1.join();
+
+ VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+ std::counting_semaphore<-1> sem(2);
+ return 0;
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::counting_semaphore<10> s(3);
+
+ s.acquire();
+ VERIFY( s.try_acquire() );
+ VERIFY( s.try_acquire() );
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+ std::binary_semaphore s(1);
+
+ s.acquire();
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+void test03()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test04()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s._M_try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s._M_try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ test01();
+ test02();
+ test03();
+ test04();
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s.try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s.try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
--
2.26.2
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] libstdc++: Add C++2a synchronization support
2020-09-28 13:25 ` Jonathan Wakely
@ 2020-10-01 23:37 ` Thomas Rodgers
2020-10-02 15:40 ` Thomas Rodgers
0 siblings, 1 reply; 35+ messages in thread
From: Thomas Rodgers @ 2020-10-01 23:37 UTC (permalink / raw)
To: gcc-patches, libstdc++; +Cc: trodgers
From: Thomas Rodgers <trodgers@redhat.com>
Updated patch incorporating latest feedback.
Add support for -
* atomic_flag::wait/notify_one/notify_all
* atomic::wait/notify_one/notify_all
* counting_semaphore
* binary_semaphore
* latch
libstdc++-v3/ChangeLog:
* include/Makefile.am (bits_headers): Add new header.
* include/Makefile.in: Regenerate.
* include/bits/atomic_base.h (__atomic_flag::wait): Define.
(__atomic_flag::notify_one): Likewise.
(__atomic_flag::notify_all): Likewise.
(__atomic_base<_Itp>::wait): Likewise.
(__atomic_base<_Itp>::notify_one): Likewise.
(__atomic_base<_Itp>::notify_all): Likewise.
(__atomic_base<_Ptp*>::wait): Likewise.
(__atomic_base<_Ptp*>::notify_one): Likewise.
(__atomic_base<_Ptp*>::notify_all): Likewise.
(__atomic_impl::wait): Likewise.
(__atomic_impl::notify_one): Likewise.
(__atomic_impl::notify_all): Likewise.
(__atomic_float<_Fp>::wait): Likewise.
(__atomic_float<_Fp>::notify_one): Likewise.
(__atomic_float<_Fp>::notify_all): Likewise.
(__atomic_ref<_Tp>::wait): Likewise.
(__atomic_ref<_Tp>::notify_one): Likewise.
(__atomic_ref<_Tp>::notify_all): Likewise.
(atomic_wait<_Tp>): Likewise.
(atomic_wait_explicit<_Tp>): Likewise.
(atomic_notify_one<_Tp>): Likewise.
(atomic_notify_all<_Tp>): Likewise.
* include/bits/atomic_wait.h: New file.
* include/bits/atomic_timed_wait.h: New file.
* include/bits/semaphore_base.h: New file.
* include/std/atomic (atomic<bool>::wait): Define.
(atomic<bool>::wait_one): Likewise.
(atomic<bool>::wait_all): Likewise.
(atomic<_Tp>::wait): Likewise.
(atomic<_Tp>::wait_one): Likewise.
(atomic<_Tp>::wait_all): Likewise.
(atomic<_Tp*>::wait): Likewise.
(atomic<_Tp*>::wait_one): Likewise.
(atomic<_Tp*>::wait_all): Likewise.
* include/std/latch: New file.
* include/std/semaphore: New file.
* include/std/version: Add __cpp_lib_semaphore and
__cpp_lib_latch defines.
* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
* testsuite/30_thread/semaphore/1.cc: New test.
* testsuite/30_thread/semaphore/2.cc: Likewise.
* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
* testsuite/30_thread/latch/1.cc: New test.
* testsuite/30_thread/latch/2.cc: New test.
* testsuite/30_thread/latch/3.cc: New test.
---
libstdc++-v3/include/Makefile.am | 5 +
libstdc++-v3/include/Makefile.in | 5 +
libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
libstdc++-v3/include/std/atomic | 73 +++++
libstdc++-v3/include/std/latch | 90 ++++++
libstdc++-v3/include/std/semaphore | 92 ++++++
libstdc++-v3/include/std/version | 2 +
.../atomic/wait_notify/atomic_refs.cc | 103 ++++++
.../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
.../29_atomics/atomic/wait_notify/floats.cc | 32 ++
.../29_atomics/atomic/wait_notify/generic.cc | 31 ++
.../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
.../atomic/wait_notify/integrals.cc | 65 ++++
.../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
.../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
.../testsuite/30_threads/semaphore/1.cc | 27 ++
.../testsuite/30_threads/semaphore/2.cc | 27 ++
.../semaphore/least_max_value_neg.cc | 30 ++
.../30_threads/semaphore/try_acquire.cc | 55 ++++
.../30_threads/semaphore/try_acquire_for.cc | 85 +++++
.../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
.../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
28 files changed, 2471 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
create mode 100644 libstdc++-v3/include/std/latch
create mode 100644 libstdc++-v3/include/std/semaphore
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
${std_srcdir}/iostream \
${std_srcdir}/istream \
${std_srcdir}/iterator \
+ ${std_srcdir}/latch \
${std_srcdir}/limits \
${std_srcdir}/list \
${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
${std_srcdir}/ratio \
${std_srcdir}/regex \
${std_srcdir}/scoped_allocator \
+ ${std_srcdir}/semaphore \
${std_srcdir}/set \
${std_srcdir}/shared_mutex \
${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
${bits_srcdir}/allocated_ptr.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/atomic_base.h \
+ ${bits_srcdir}/atomic_wait.h \
+ ${bits_srcdir}/atomic_timed_wait.h \
${bits_srcdir}/atomic_futex.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
${bits_srcdir}/regex_compiler.tcc \
${bits_srcdir}/regex_executor.h \
${bits_srcdir}/regex_executor.tcc \
+ ${bits_srcdir}/semaphore_base.h \
${bits_srcdir}/shared_ptr.h \
${bits_srcdir}/shared_ptr_atomic.h \
${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
#include <bits/atomic_lockfree_defines.h>
#include <bits/move.h>
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
#ifndef _GLIBCXX_ALWAYS_INLINE
#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
-
// Base types for atomics.
template<typename _IntTp>
struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_load(&_M_i, &__v, int(__m));
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
}
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(bool __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]()
+ { return this->test(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
#endif // C++20
_GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__int_type __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __int_type
fetch_add(__int_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__m1), int(__m2));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__pointer_type __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(&_M_p, __old,
+ [__m, this, __old]()
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_p, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_p, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__success), int(__failure));
}
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(const _Tp* __ptr, _Val<_Tp> __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(__ptr, __old,
+ [=]() { return load(__ptr, __m) == __old; });
+ }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, false); }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE _Tp
fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(&_M_fp); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(&_M_fp); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
private:
_Tp* _M_ptr;
};
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ enum class __atomic_wait_status { no_timeout, timeout };
+
+ namespace __detail
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __platform_wait_clock_t = chrono::steady_clock;
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until_impl(__platform_wait_t* __addr,
+ __platform_wait_t __val,
+ const chrono::time_point<__platform_wait_clock_t,
+ _Duration>& __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())
+ };
+
+ auto __e = syscall (SYS_futex, __addr,
+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+ __val, &__rt, nullptr,
+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+ std::terminate();
+ return (__platform_wait_clock_t::now() < __atime)
+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+ }
+
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+ {
+ return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __platform_wait_clock_t::time_point __s_entry =
+ __platform_wait_clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
+ __atomic_wait_status::no_timeout)
+ return __atomic_wait_status::no_timeout;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+ }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<mutex>& __lock,
+ 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())
+ };
+
+ pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+ CLOCK_MONOTONIC,
+ &__ts);
+ return (chrono::steady_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+ }
+#endif
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ 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_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+ &__ts);
+ return (chrono::system_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
+
+ // return true if timeout
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ using __clock_t = chrono::steady_clock;
+#else
+ using __clock_t = chrono::system_clock;
+#endif
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+ return __atomic_wait_status::no_timeout;
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+
+ struct __timed_waiters : __waiters
+ {
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ _M_do_wait_until(__platform_wait_t __version,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+ __platform_wait_t __cur = 0;
+ __waiters::__lock_t __l(_M_mtx);
+ while (__cur <= __version)
+ {
+ if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
+ __atomic_wait_status::timeout)
+ return __atomic_wait_status::timeout;
+
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+ return __atomic_wait_status::no_timeout;
+#endif
+ }
+
+ static __timed_waiters&
+ _S_timed_for(void* __t)
+ {
+ static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+ return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+ }
+ };
+ } // namespace __detail
+
+ template<typename _Tp, typename _Pred,
+ typename _Clock, typename _Duration>
+ bool
+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+ auto __version = __w._M_enter_wait();
+ do
+ {
+ __atomic_wait_status __res;
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+ __old,
+ __atime);
+ }
+ else
+ {
+ __res = __w._M_do_wait_until(__version, __atime);
+ }
+ if (__res == __atomic_wait_status::timeout)
+ return false;
+ }
+ while (!__pred() && __atime < _Clock::now());
+ __w._M_leave_wait();
+
+ // if timed out, return false
+ return (_Clock::now() < __atime);
+ }
+
+ template<typename _Tp, typename _Pred,
+ typename _Rep, typename _Period>
+ bool
+ __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ if (!__rtime.count())
+ return false; // no rtime supplied, and spin did not acquire
+
+ using __dur = chrono::steady_clock::duration;
+ auto __reltime = chrono::duration_cast<__dur>(__rtime);
+ if (__reltime < __rtime)
+ ++__reltime;
+
+
+ return __atomic_wait_until(__addr, __old, std::move(__pred),
+ chrono::steady_clock::now() + __reltime);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..21ec3d38c94
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,301 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __detail
+ {
+ using __platform_wait_t = int;
+
+ constexpr auto __atomic_spin_count_1 = 16;
+ constexpr auto __atomic_spin_count_2 = 12;
+
+ inline constexpr
+ auto __platform_wait_max_value =
+ __gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+ template<typename _Tp>
+ inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ = is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+ = false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ enum class __futex_wait_flags : int
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+ __private_flag = 128,
+#else
+ __private_flag = 0,
+#endif
+ __wait = 0,
+ __wake = 1,
+ __wait_bitset = 9,
+ __wake_bitset = 10,
+ __wait_private = __wait | __private_flag,
+ __wake_private = __wake | __private_flag,
+ __wait_bitset_private = __wait_bitset | __private_flag,
+ __wake_bitset_private = __wake_bitset | __private_flag,
+ __bitset_match_any = -1
+ };
+
+ template<typename _Tp>
+ void
+ __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+ {
+ auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wait_private),
+ __val, nullptr);
+ if (__e && !(errno == EINTR || errno == EAGAIN))
+ std::terminate();
+ }
+
+ template<typename _Tp>
+ void
+ __platform_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wake_private),
+ __all ? INT_MAX : 1);
+ }
+#endif
+
+ struct __waiters
+ {
+ __platform_wait_t alignas(64) _M_ver = 0;
+ __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __lock_t = std::unique_lock<std::mutex>;
+ mutable __lock_t::mutex_type _M_mtx;
+
+# ifdef __GTHREAD_COND_INIT
+ mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+ __waiters() noexcept = default;
+# else
+ mutable __gthread_cond_t _M_cv;
+ __waiters() noexcept
+ {
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+ }
+# endif
+#endif
+
+ __platform_wait_t
+ _M_enter_wait() noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+ __atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ return __res;
+ }
+
+ void
+ _M_leave_wait() noexcept
+ {
+ __atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ }
+
+ void
+ _M_do_wait(__platform_wait_t __version) noexcept
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_wait(&_M_ver, __version);
+#else
+ __platform_wait_t __cur = 0;
+ while (__cur <= __version)
+ {
+ __waiters::__lock_t __l(_M_mtx);
+ auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+ if (__e)
+ std::terminate();
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+#endif
+ }
+
+ __platform_wait_t
+ _M_waiting() const noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
+
+ void
+ _M_notify(bool __all) noexcept
+ {
+ __atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_notify(&_M_ver, __all);
+#else
+ auto __e = __gthread_cond_broadcast(&_M_cv);
+ if (__e)
+ __throw_system_error(__e);
+#endif
+ }
+
+ static __waiters&
+ _S_for(const void* __t)
+ {
+ const unsigned char __mask = 0xf;
+ static __waiters __w[__mask + 1];
+
+ auto __key = _Hash_impl::hash(__t) & __mask;
+ return __w[__key];
+ }
+ };
+
+ struct __waiter
+ {
+ __waiters& _M_w;
+ __platform_wait_t _M_version;
+
+ template<typename _Tp>
+ __waiter(const _Tp* __addr) noexcept
+ : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+ , _M_version(_M_w._M_enter_wait())
+ { }
+
+ ~__waiter()
+ { _M_w._M_leave_wait(); }
+
+ void _M_do_wait() noexcept
+ { _M_w._M_do_wait(_M_version); }
+ };
+
+ void
+ __thread_relax() noexcept
+ {
+#if defined __i386__ || defined __x86_64__
+ __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ void
+ __thread_yield() noexcept
+ {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ } // namespace __detail
+
+ template<typename _Pred>
+ bool
+ __atomic_spin(_Pred __pred) noexcept
+ {
+ for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+ {
+ if (__pred())
+ return true;
+
+ if (__i < __detail::__atomic_spin_count_2)
+ __detail::__thread_relax();
+ else
+ __detail::__thread_yield();
+ }
+ return false;
+ }
+
+ template<typename _Tp, typename _Pred>
+ void
+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+ {
+ using namespace __detail;
+ if (__atomic_spin(__pred))
+ return;
+
+ __waiter __w(__addr);
+ while (!__pred())
+ {
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_wait(__addr, __old);
+ }
+ else
+ {
+ // TODO support timed backoff when this can be moved into the lib
+ __w._M_do_wait();
+ }
+ }
+ }
+
+ template<typename _Tp>
+ void
+ __atomic_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ using namespace __detail;
+ auto& __w = __waiters::_S_for((void*)__addr);
+ if (!__w._M_waiting())
+ return;
+
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+ }
+ else
+ {
+ __w._M_notify(__all);
+ }
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..ed127a7a953
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#include <iostream>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ struct __platform_semaphore
+ {
+ using __clock_t = chrono::system_clock;
+ static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+ explicit __platform_semaphore(ptrdiff_t __count) noexcept
+ {
+ sem_init(&_M_semaphore, 0, __count);
+ }
+
+ __platform_semaphore(const __platform_semaphore&) = delete;
+ __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+ ~__platform_semaphore()
+ { sem_destroy(&_M_semaphore); }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ for (;;)
+ {
+ auto __err = sem_wait(&_M_semaphore);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(std::ptrdiff_t __update) noexcept
+ {
+ for(; __update != 0; --__update)
+ {
+ auto __err = sem_post(&_M_semaphore);
+ if (__err)
+ std::terminate();
+ }
+ }
+
+ bool
+ _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
+ {
+
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ struct timespec __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ for (;;)
+ {
+ auto __err = sem_timedwait(&_M_semaphore, &__ts);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err && (errno == ETIMEDOUT))
+ return false;
+ else if (__err && (errno == EINVAL))
+ return false; // caller supplied an invalid __atime
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ return true;
+ }
+
+ template<typename _Clock, typename _Duration>
+ bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ if constexpr (std::is_same<__clock_t, _Clock>::value)
+ {
+ return _M_try_acquire_until_impl(__atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (_M_try_acquire_until_impl(__s_atime))
+ return true;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ return (_Clock::now() < __atime);
+ }
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+ private:
+ sem_t _M_semaphore;
+ };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+ template<typename _Tp>
+ struct __atomic_semaphore
+ {
+ static_assert(std::is_integral_v<_Tp>);
+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+ explicit __atomic_semaphore(_Tp __count) noexcept
+ : _M_a(__count)
+ { }
+
+ __atomic_semaphore(const __atomic_semaphore&) = delete;
+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ __atomic_wait(&_M_a, __old, __pred);
+ }
+
+ bool
+ _M_try_acquire() noexcept
+ {
+ auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ if (__old == 0)
+ return false;
+
+ return __atomic_spin([this, &__old]
+ {
+ return __atomic_impl::compare_exchange_weak(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ });
+ }
+
+ template<typename _Clock, typename _Duration>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ return __atomic_wait_until(&_M_a, __old, __pred, __atime);
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(ptrdiff_t __update) noexcept
+ {
+ if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
+ return;
+ if (__update > 1)
+ __atomic_impl::notify_all(&_M_a);
+ else
+ __atomic_impl::notify_one(&_M_a);
+ }
+
+ private:
+ alignas(__alignof__(_Tp)) _Tp _M_a;
+ };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+ // Use futex if available and didn't force use of POSIX
+ using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ using __fast_semaphore = __platform_semaphore;
+#else
+ using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+ using __semaphore_impl = conditional_t<
+ (__least_max_value > 1),
+ conditional_t<
+ (__least_max_value <= __fast_semaphore::_S_max),
+ __fast_semaphore,
+ __atomic_semaphore<ptrdiff_t>>,
+ __fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..c15909d9ccb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
compare_exchange_strong(bool& __i1, bool __i2,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+ void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { _M_base.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_base.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_base.notify_all(); }
+#endif
};
#if __cplusplus <= 201703L
@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return compare_exchange_strong(__e, __i, __m,
__cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+ void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ {
+ const auto __v = this->load(__m);
+ // TODO make this ignore padding bits when we can do that
+ return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
+ });
+ }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ void notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+#endif
+
};
#undef _GLIBCXX20_INIT
@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+ { _M_b.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_b.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_b.notify_all(); }
+#endif
__pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order_seq_cst);
}
+
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ inline void
+ atomic_wait(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old) noexcept
+ { __a->wait(__old); }
+
+ template<typename _Tp>
+ inline void
+ atomic_wait_explicit(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old,
+ std::memory_order __m) noexcept
+ { __a->wait(__old, __m); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_one(atomic<_Tp>* __a) noexcept
+ { __a->notify_one(); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_all(atomic<_Tp>* __a) noexcept
+ { __a->notify_all(); }
+
+#endif // C++2a
+
// Function templates for atomic_integral and atomic_pointer operations only.
// Some operations (and, or, xor) are only available for atomic integrals,
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..bd06db5aa7f
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,90 @@
+// <latch> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ class latch
+ {
+ public:
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+ constexpr explicit latch(ptrdiff_t __expected) noexcept
+ : _M_a(__expected) { }
+
+ ~latch() = default;
+ latch(const latch&) = delete;
+ latch& operator=(const latch&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ count_down(ptrdiff_t __update = 1)
+ {
+ auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
+ if (__old == __update)
+ __atomic_impl::notify_all(&_M_a);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE bool
+ try_wait() const noexcept
+ { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait() const
+ {
+ auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ arrive_and_wait(ptrdiff_t __update = 1)
+ {
+ count_down();
+ wait();
+ }
+
+ private:
+ alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+ };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..865d6c4aecb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<ptrdiff_t __least_max_value =
+ __gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
+ class counting_semaphore
+ {
+ static_assert(__least_max_value >= 0);
+
+ __semaphore_impl<__least_max_value> _M_sem;
+
+ public:
+ explicit counting_semaphore(ptrdiff_t __desired) noexcept
+ : _M_sem(__desired)
+ { }
+
+ ~counting_semaphore() = default;
+
+ counting_semaphore(const counting_semaphore&) = delete;
+ counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __least_max_value; }
+
+ void
+ release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+ { _M_sem._M_release(__update); }
+
+ void
+ acquire() noexcept(noexcept(_M_sem._M_acquire()))
+ { _M_sem._M_acquire(); }
+
+ bool
+ try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+ { return _M_sem._M_try_acquire(); }
+
+ template<class _Rep, class _Period>
+ bool
+ try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+ { return _M_sem._M_try_acquire_for(__rtime); }
+
+ template<class _Clock, class _Dur>
+ bool
+ try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+ { return _M_sem._M_try_acquire_until(__atime); }
+ };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..b9c7c6c62a8 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,12 +216,14 @@
#ifdef _GLIBCXX_HAS_GTHREADS
# define __cpp_lib_jthread 201911L
#endif
+#define __cpp_lib_latch 201907L
#define __cpp_lib_list_remove_return_type 201806L
#define __cpp_lib_math_constants 201907L
#define __cpp_lib_polymorphic_allocator 201902L
#if __cpp_lib_concepts
# define __cpp_lib_ranges 201911L
#endif
+#define __cpp_lib_semaphore 201907L
#define __cpp_lib_shift 201806L
#define __cpp_lib_span 202002L
#define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ Tp aa = val1;
+ std::atomic_ref<Tp> a(aa);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp,
+ bool = std::is_integral_v<Tp>
+ || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+ check()
+ {
+ Tp a = 0;
+ Tp b = 42;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+ check(Tp b)
+ {
+ Tp a;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+struct foo
+{
+ long a = 0;
+ long b = 0;
+
+ foo& operator=(foo const&) = default;
+
+ friend bool
+ operator==(foo const& rhs, foo const& lhs)
+ { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+ check<long>();
+ check<double>();
+ check<foo>({42, 48});
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..b9fc063c66f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<bool> a(false);
+ std::atomic<bool> b(false);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ if (a.load())
+ {
+ b.store(true);
+ }
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(true);
+ a.notify_one();
+ t.join();
+ VERIFY( b.load() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
new file mode 100644
index 00000000000..1d032085752
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+int
+main ()
+{
+ check<float> f;
+ check<double> d;
+ check<long double> l;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..d15b9c86ae6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+int
+main ()
+{
+ struct S{ int i; };
+ check<S> check_s{S{0},S{42}};
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,160 @@
+// 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+ check(Tp a = 0, Tp b = 42)
+ {
+ if constexpr (std::equality_comparable<Tp>)
+ {
+ VERIFY( check_wait_notify(a, b) == b);
+ VERIFY( check_atomic_wait_notify(a, b) == b);
+ }
+ else
+ {
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+ }
+
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_atomic_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+ }
+ }
+ }
+};
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
new file mode 100644
index 00000000000..115cb79a040
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+void
+test01()
+{
+ struct S{ int i; };
+ std::atomic<S> s;
+
+ s.wait(S{42});
+}
+
+int
+main ()
+{
+ // check<bool> bb;
+ check<char> ch;
+ check<signed char> sch;
+ check<unsigned char> uch;
+ check<short> s;
+ check<unsigned short> us;
+ check<int> i;
+ check<unsigned int> ui;
+ check<long> l;
+ check<unsigned long> ul;
+ check<long long> ll;
+ check<unsigned long long> ull;
+
+ check<wchar_t> wch;
+ check<char8_t> ch8;
+ check<char16_t> ch16;
+ check<char32_t> ch32;
+
+ check<int8_t> i8;
+ check<int16_t> i16;
+ check<int32_t> i32;
+ check<int64_t> i64;
+
+ check<uint8_t> u8;
+ check<uint16_t> u16;
+ check<uint32_t> u32;
+ check<uint64_t> u64;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ long aa;
+ long bb;
+
+ std::atomic<long*> a(nullptr);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(nullptr);
+ if (a.load() == &aa)
+ a.store(&bb);
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(&aa);
+ a.notify_one();
+ t.join();
+ VERIFY( a.load() == &bb);
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..6de7873ecc2
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic_flag a;
+ std::atomic_flag b;
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ b.test_and_set();
+ b.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.test_and_set();
+ a.notify_one();
+ b.wait(false);
+ t.join();
+
+ VERIFY( a.test() );
+ VERIFY( b.test() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+ std::atomic<int> a(0);
+
+ std::latch l(3);
+
+ VERIFY( !l.try_wait() );
+
+ auto fn = [&]
+ {
+ ++a;
+ l.count_down();
+ };
+
+ std::thread t0(fn);
+ std::thread t1(fn);
+
+ l.arrive_and_wait();
+ t0.join();
+ t1.join();
+
+ VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+ std::counting_semaphore<-1> sem(2);
+ return 0;
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::counting_semaphore<10> s(3);
+
+ s.acquire();
+ VERIFY( s.try_acquire() );
+ VERIFY( s.try_acquire() );
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+ std::binary_semaphore s(1);
+
+ s.acquire();
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+void test03()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test04()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s._M_try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s._M_try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ test01();
+ test02();
+ test03();
+ test04();
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s.try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s.try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
--
2.26.2
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-09-28 21:29 ` Thomas Rodgers
@ 2020-09-29 9:44 ` Jonathan Wakely
0 siblings, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-09-29 9:44 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: Thomas Rodgers, gcc-patches, libstdc++
On 28/09/20 14:29 -0700, Thomas Rodgers wrote:
>>>+ template<typename _Duration>
>>>+ __atomic_wait_status
>>>+ __platform_wait_until_impl(__platform_wait_t* __addr,
>>>+ __platform_wait_t __val,
>>>+ const chrono::time_point<__platform_wait_clock_t,
>>>+ _Duration>& __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())
>>>+ };
>>>+
>>>+ auto __e = syscall (SYS_futex, __addr,
>>>+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>>>+ __val, &__rt, nullptr,
>>>+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
>>>+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>>>+ std::terminate();
>>>+ return (__platform_wait_clock_t::now() < __atime)
>>>+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>>>+ }
>>>+
>>>+ template<typename _Clock, typename _Duration>
>>>+ __atomic_wait_status
>>>+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>>>+ const chrono::time_point<_Clock, _Duration>& __atime)
>>>+ {
>>>+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
>>
>> This case is impossible, since the other overload would be selected
>> if the clock is the __platform_wait_clock_t (unless the caller says
>> __platform_wait_until<__platform_wait_until> to explicitly call this
>> overload, but users can't call this function, and we won't do that).
>>
>
>Which overload?
I must have misread __platform_wait_until_impl above as
__platform_wait_until. Ignore this comment, sorry!
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-09-28 13:36 ` Jonathan Wakely
@ 2020-09-28 21:29 ` Thomas Rodgers
2020-09-29 9:44 ` Jonathan Wakely
0 siblings, 1 reply; 35+ messages in thread
From: Thomas Rodgers @ 2020-09-28 21:29 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Thomas Rodgers, gcc-patches, libstdc++
Jonathan Wakely writes:
> On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>>From: Thomas Rodgers <trodgers@redhat.com>
>>
>>This patch supercedes both the Add C++2a synchronization support patch
>>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>>
>>Add support for -
>> * atomic_flag::wait/notify_one/notify_all
>> * atomic::wait/notify_one/notify_all
>> * counting_semaphore
>> * binary_semaphore
>> * latch
>>
>>libstdc++-v3/ChangeLog:
>>
>> * include/Makefile.am (bits_headers): Add new header.
>> * include/Makefile.in: Regenerate.
>> * include/bits/atomic_base.h (__atomic_flag::wait): Define.
>> (__atomic_flag::notify_one): Likewise.
>> (__atomic_flag::notify_all): Likewise.
>> (__atomic_base<_Itp>::wait): Likewise.
>> (__atomic_base<_Itp>::notify_one): Likewise.
>> (__atomic_base<_Itp>::notify_all): Likewise.
>> (__atomic_base<_Ptp*>::wait): Likewise.
>> (__atomic_base<_Ptp*>::notify_one): Likewise.
>> (__atomic_base<_Ptp*>::notify_all): Likewise.
>> (__atomic_impl::wait): Likewise.
>> (__atomic_impl::notify_one): Likewise.
>> (__atomic_impl::notify_all): Likewise.
>> (__atomic_float<_Fp>::wait): Likewise.
>> (__atomic_float<_Fp>::notify_one): Likewise.
>> (__atomic_float<_Fp>::notify_all): Likewise.
>> (__atomic_ref<_Tp>::wait): Likewise.
>> (__atomic_ref<_Tp>::notify_one): Likewise.
>> (__atomic_ref<_Tp>::notify_all): Likewise.
>> (atomic_wait<_Tp>): Likewise.
>> (atomic_wait_explicit<_Tp>): Likewise.
>> (atomic_notify_one<_Tp>): Likewise.
>> (atomic_notify_all<_Tp>): Likewise.
>> * include/bits/atomic_wait.h: New file.
>> * include/bits/atomic_timed_wait.h: New file.
>> * include/bits/semaphore_base.h: New file.
>> * include/std/atomic (atomic<bool>::wait): Define.
>> (atomic<bool>::wait_one): Likewise.
>> (atomic<bool>::wait_all): Likewise.
>> (atomic<_Tp>::wait): Likewise.
>> (atomic<_Tp>::wait_one): Likewise.
>> (atomic<_Tp>::wait_all): Likewise.
>> (atomic<_Tp*>::wait): Likewise.
>> (atomic<_Tp*>::wait_one): Likewise.
>> (atomic<_Tp*>::wait_all): Likewise.
>> * include/std/latch: New file.
>> * include/std/semaphore: New file.
>> * include/std/version: Add __cpp_lib_semaphore and
>> __cpp_lib_latch defines.
>> * testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
>> * testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
>> * testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
>> * testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
>> * testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
>> * testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
>> * testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
>> * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
>> * testsuite/30_thread/semaphore/1.cc: New test.
>> * testsuite/30_thread/semaphore/2.cc: Likewise.
>> * testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
>> * testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
>> * testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
>> * testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
>> * testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
>> * testsuite/30_thread/latch/1.cc: New test.
>> * testsuite/30_thread/latch/2.cc: New test.
>> * testsuite/30_thread/latch/3.cc: New test.
>>---
>> libstdc++-v3/include/Makefile.am | 5 +
>> libstdc++-v3/include/Makefile.in | 5 +
>> libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
>> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
>> libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
>> libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
>> libstdc++-v3/include/std/atomic | 73 +++++
>> libstdc++-v3/include/std/latch | 90 ++++++
>> libstdc++-v3/include/std/semaphore | 92 ++++++
>> libstdc++-v3/include/std/version | 2 +
>> .../atomic/wait_notify/atomic_refs.cc | 103 ++++++
>> .../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
>> .../29_atomics/atomic/wait_notify/floats.cc | 32 ++
>> .../29_atomics/atomic/wait_notify/generic.cc | 31 ++
>> .../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
>> .../atomic/wait_notify/integrals.cc | 65 ++++
>> .../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
>> .../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
>> libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
>> libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
>> libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
>> .../testsuite/30_threads/semaphore/1.cc | 27 ++
>> .../testsuite/30_threads/semaphore/2.cc | 27 ++
>> .../semaphore/least_max_value_neg.cc | 30 ++
>> .../30_threads/semaphore/try_acquire.cc | 55 ++++
>> .../30_threads/semaphore/try_acquire_for.cc | 85 +++++
>> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
>> .../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
>> 28 files changed, 2471 insertions(+), 1 deletion(-)
>> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
>> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
>> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
>> create mode 100644 libstdc++-v3/include/std/latch
>> create mode 100644 libstdc++-v3/include/std/semaphore
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>>
>>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>>index c9df9a9d6c6..9b5b6ed0005 100644
>>--- a/libstdc++-v3/include/Makefile.am
>>+++ b/libstdc++-v3/include/Makefile.am
>>@@ -52,6 +52,7 @@ std_headers = \
>> ${std_srcdir}/iostream \
>> ${std_srcdir}/istream \
>> ${std_srcdir}/iterator \
>>+ ${std_srcdir}/latch \
>> ${std_srcdir}/limits \
>> ${std_srcdir}/list \
>> ${std_srcdir}/locale \
>>@@ -69,6 +70,7 @@ std_headers = \
>> ${std_srcdir}/ratio \
>> ${std_srcdir}/regex \
>> ${std_srcdir}/scoped_allocator \
>>+ ${std_srcdir}/semaphore \
>> ${std_srcdir}/set \
>> ${std_srcdir}/shared_mutex \
>> ${std_srcdir}/span \
>>@@ -101,6 +103,8 @@ bits_headers = \
>> ${bits_srcdir}/allocated_ptr.h \
>> ${bits_srcdir}/allocator.h \
>> ${bits_srcdir}/atomic_base.h \
>>+ ${bits_srcdir}/atomic_wait.h \
>>+ ${bits_srcdir}/atomic_timed_wait.h \
>> ${bits_srcdir}/atomic_futex.h \
>> ${bits_srcdir}/basic_ios.h \
>> ${bits_srcdir}/basic_ios.tcc \
>>@@ -175,6 +179,7 @@ bits_headers = \
>> ${bits_srcdir}/regex_compiler.tcc \
>> ${bits_srcdir}/regex_executor.h \
>> ${bits_srcdir}/regex_executor.tcc \
>>+ ${bits_srcdir}/semaphore_base.h \
>> ${bits_srcdir}/shared_ptr.h \
>> ${bits_srcdir}/shared_ptr_atomic.h \
>> ${bits_srcdir}/shared_ptr_base.h \
>>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>>index 2cdd2bd6cae..dd4db926592 100644
>>--- a/libstdc++-v3/include/bits/atomic_base.h
>>+++ b/libstdc++-v3/include/bits/atomic_base.h
>>@@ -37,6 +37,10 @@
>> #include <bits/atomic_lockfree_defines.h>
>> #include <bits/move.h>
>>
>>+#if __cplusplus > 201703L
>>+#include <bits/atomic_wait.h>
>>+#endif
>>+
>> #ifndef _GLIBCXX_ALWAYS_INLINE
>> #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
>> #endif
>>@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> return __ret;
>> }
>>
>>-
>> // Base types for atomics.
>> template<typename _IntTp>
>> struct __atomic_base;
>>@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __atomic_load(&_M_i, &__v, int(__m));
>> return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
>> }
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(bool __old,
>>+ memory_order __m = memory_order_seq_cst) const noexcept
>>+ {
>>+ std::__atomic_wait(&_M_i, __old,
>>+ [__m, this, __old]()
>>+ { return this->test(__m) != __old; });
>>+ }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { std::__atomic_notify(&_M_i, false); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { std::__atomic_notify(&_M_i, true); }
>>+
>>+ // TODO add const volatile overload
>> #endif // C++20
>>
>> _GLIBCXX_ALWAYS_INLINE void
>>@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __cmpexch_failure_order(__m));
>> }
>>
>>+#if __cplusplus > 201703L
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(__int_type __old,
>>+ memory_order __m = memory_order_seq_cst) const noexcept
>>+ {
>>+ std::__atomic_wait(&_M_i, __old,
>>+ [__m, this, __old]
>>+ { return this->load(__m) != __old; });
>>+ }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { std::__atomic_notify(&_M_i, false); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { std::__atomic_notify(&_M_i, true); }
>>+
>>+ // TODO add const volatile overload
>>+#endif // C++2a
>>+
>> _GLIBCXX_ALWAYS_INLINE __int_type
>> fetch_add(__int_type __i,
>> memory_order __m = memory_order_seq_cst) noexcept
>>@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> int(__m1), int(__m2));
>> }
>>
>>+#if __cplusplus > 201703L
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(__pointer_type __old,
>>+ memory_order __m = memory_order_seq_cst) noexcept
>>+ {
>>+ std::__atomic_wait(&_M_p, __old,
>>+ [__m, this, __old]()
>>+ { return this->load(__m) != __old; });
>>+ }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { std::__atomic_notify(&_M_p, false); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { std::__atomic_notify(&_M_p, true); }
>>+
>>+ // TODO add const volatile overload
>>+#endif // C++2a
>>+
>> _GLIBCXX_ALWAYS_INLINE __pointer_type
>> fetch_add(ptrdiff_t __d,
>> memory_order __m = memory_order_seq_cst) noexcept
>>@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> int(__success), int(__failure));
>> }
>>
>>+#if __cplusplus > 201703L
>>+ template<typename _Tp>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(const _Tp* __ptr, _Val<_Tp> __old,
>>+ memory_order __m = memory_order_seq_cst) noexcept
>>+ {
>>+ std::__atomic_wait(__ptr, __old,
>>+ [=]() { return load(__ptr, __m) == __old; });
>>+ }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ template<typename _Tp>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one(const _Tp* __ptr) noexcept
>>+ { std::__atomic_notify(__ptr, false); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ template<typename _Tp>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all(const _Tp* __ptr) noexcept
>>+ { std::__atomic_notify(__ptr, true); }
>>+
>>+ // TODO add const volatile overload
>>+#endif // C++2a
>>+
>> template<typename _Tp>
>> _GLIBCXX_ALWAYS_INLINE _Tp
>> fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
>>@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __cmpexch_failure_order(__order));
>> }
>>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+ { __atomic_impl::wait(&_M_fp, __old, __m); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { __atomic_impl::notify_one(&_M_fp); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { __atomic_impl::notify_all(&_M_fp); }
>>+
>>+ // TODO add const volatile overload
>>+
>> value_type
>> fetch_add(value_type __i,
>> memory_order __m = memory_order_seq_cst) noexcept
>>@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __cmpexch_failure_order(__order));
>> }
>>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>> private:
>> _Tp* _M_ptr;
>> };
>>@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __cmpexch_failure_order(__order));
>> }
>>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>> value_type
>> fetch_add(value_type __i,
>> memory_order __m = memory_order_seq_cst) const noexcept
>>@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __cmpexch_failure_order(__order));
>> }
>>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>> value_type
>> fetch_add(value_type __i,
>> memory_order __m = memory_order_seq_cst) const noexcept
>>@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __cmpexch_failure_order(__order));
>> }
>>
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_one() const noexcept
>>+ { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>>+ _GLIBCXX_ALWAYS_INLINE void
>>+ notify_all() const noexcept
>>+ { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+ // TODO add const volatile overload
>>+
>> _GLIBCXX_ALWAYS_INLINE value_type
>> fetch_add(difference_type __d,
>> memory_order __m = memory_order_seq_cst) const noexcept
>>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>new file mode 100644
>>index 00000000000..2f57356b366
>>--- /dev/null
>>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>@@ -0,0 +1,281 @@
>>+// -*- C++ -*- header.
>>+
>>+// 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.
>>+
>>+// Under Section 7 of GPL version 3, you are granted additional
>>+// permissions described in the GCC Runtime Library Exception, version
>>+// 3.1, as published by the Free Software Foundation.
>>+
>>+// You should have received a copy of the GNU General Public License and
>>+// a copy of the GCC Runtime Library Exception along with this program;
>>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>>+// <http://www.gnu.org/licenses/>.
>>+
>>+/** @file bits/atomic_timed_wait.h
>>+ * This is an internal header file, included by other library headers.
>>+ * Do not attempt to use it directly. @headername{atomic}
>>+ */
>>+
>>+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
>>+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
>>+
>>+#pragma GCC system_header
>>+
>>+#include <bits/c++config.h>
>>+#include <bits/functional_hash.h>
>>+#include <bits/atomic_wait.h>
>>+
>>+#include <chrono>
>>+
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+#include <sys/time.h>
>>+#endif
>>+
>>+namespace std _GLIBCXX_VISIBILITY(default)
>>+{
>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>+
>>+ enum class __atomic_wait_status { no_timeout, timeout };
>>+
>>+ namespace __detail
>>+ {
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+ using __platform_wait_clock_t = chrono::steady_clock;
>>+
>>+ template<typename _Duration>
>>+ __atomic_wait_status
>>+ __platform_wait_until_impl(__platform_wait_t* __addr,
>>+ __platform_wait_t __val,
>>+ const chrono::time_point<__platform_wait_clock_t,
>>+ _Duration>& __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())
>>+ };
>>+
>>+ auto __e = syscall (SYS_futex, __addr,
>>+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>>+ __val, &__rt, nullptr,
>>+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
>>+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>>+ std::terminate();
>>+ return (__platform_wait_clock_t::now() < __atime)
>>+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>>+ }
>>+
>>+ template<typename _Clock, typename _Duration>
>>+ __atomic_wait_status
>>+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>>+ const chrono::time_point<_Clock, _Duration>& __atime)
>>+ {
>>+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
>
> This case is impossible, since the other overload would be selected
> if the clock is the __platform_wait_clock_t (unless the caller says
> __platform_wait_until<__platform_wait_until> to explicitly call this
> overload, but users can't call this function, and we won't do that).
>
Which overload?
>>+ {
>>+ return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
>>+ }
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-09-11 23:58 ` [PATCH] libstdc++: " Thomas Rodgers
2020-09-28 13:25 ` Jonathan Wakely
2020-09-28 13:30 ` Jonathan Wakely
@ 2020-09-28 13:36 ` Jonathan Wakely
2020-09-28 21:29 ` Thomas Rodgers
2 siblings, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-09-28 13:36 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers
On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This patch supercedes both the Add C++2a synchronization support patch
>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>
>Add support for -
> * atomic_flag::wait/notify_one/notify_all
> * atomic::wait/notify_one/notify_all
> * counting_semaphore
> * binary_semaphore
> * latch
>
>libstdc++-v3/ChangeLog:
>
> * include/Makefile.am (bits_headers): Add new header.
> * include/Makefile.in: Regenerate.
> * include/bits/atomic_base.h (__atomic_flag::wait): Define.
> (__atomic_flag::notify_one): Likewise.
> (__atomic_flag::notify_all): Likewise.
> (__atomic_base<_Itp>::wait): Likewise.
> (__atomic_base<_Itp>::notify_one): Likewise.
> (__atomic_base<_Itp>::notify_all): Likewise.
> (__atomic_base<_Ptp*>::wait): Likewise.
> (__atomic_base<_Ptp*>::notify_one): Likewise.
> (__atomic_base<_Ptp*>::notify_all): Likewise.
> (__atomic_impl::wait): Likewise.
> (__atomic_impl::notify_one): Likewise.
> (__atomic_impl::notify_all): Likewise.
> (__atomic_float<_Fp>::wait): Likewise.
> (__atomic_float<_Fp>::notify_one): Likewise.
> (__atomic_float<_Fp>::notify_all): Likewise.
> (__atomic_ref<_Tp>::wait): Likewise.
> (__atomic_ref<_Tp>::notify_one): Likewise.
> (__atomic_ref<_Tp>::notify_all): Likewise.
> (atomic_wait<_Tp>): Likewise.
> (atomic_wait_explicit<_Tp>): Likewise.
> (atomic_notify_one<_Tp>): Likewise.
> (atomic_notify_all<_Tp>): Likewise.
> * include/bits/atomic_wait.h: New file.
> * include/bits/atomic_timed_wait.h: New file.
> * include/bits/semaphore_base.h: New file.
> * include/std/atomic (atomic<bool>::wait): Define.
> (atomic<bool>::wait_one): Likewise.
> (atomic<bool>::wait_all): Likewise.
> (atomic<_Tp>::wait): Likewise.
> (atomic<_Tp>::wait_one): Likewise.
> (atomic<_Tp>::wait_all): Likewise.
> (atomic<_Tp*>::wait): Likewise.
> (atomic<_Tp*>::wait_one): Likewise.
> (atomic<_Tp*>::wait_all): Likewise.
> * include/std/latch: New file.
> * include/std/semaphore: New file.
> * include/std/version: Add __cpp_lib_semaphore and
> __cpp_lib_latch defines.
> * testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
> * testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
> * testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
> * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
> * testsuite/30_thread/semaphore/1.cc: New test.
> * testsuite/30_thread/semaphore/2.cc: Likewise.
> * testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
> * testsuite/30_thread/latch/1.cc: New test.
> * testsuite/30_thread/latch/2.cc: New test.
> * testsuite/30_thread/latch/3.cc: New test.
>---
> libstdc++-v3/include/Makefile.am | 5 +
> libstdc++-v3/include/Makefile.in | 5 +
> libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
> libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
> libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
> libstdc++-v3/include/std/atomic | 73 +++++
> libstdc++-v3/include/std/latch | 90 ++++++
> libstdc++-v3/include/std/semaphore | 92 ++++++
> libstdc++-v3/include/std/version | 2 +
> .../atomic/wait_notify/atomic_refs.cc | 103 ++++++
> .../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
> .../29_atomics/atomic/wait_notify/floats.cc | 32 ++
> .../29_atomics/atomic/wait_notify/generic.cc | 31 ++
> .../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
> .../atomic/wait_notify/integrals.cc | 65 ++++
> .../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
> .../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
> libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
> libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
> libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
> .../testsuite/30_threads/semaphore/1.cc | 27 ++
> .../testsuite/30_threads/semaphore/2.cc | 27 ++
> .../semaphore/least_max_value_neg.cc | 30 ++
> .../30_threads/semaphore/try_acquire.cc | 55 ++++
> .../30_threads/semaphore/try_acquire_for.cc | 85 +++++
> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
> .../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
> 28 files changed, 2471 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
> create mode 100644 libstdc++-v3/include/std/latch
> create mode 100644 libstdc++-v3/include/std/semaphore
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index c9df9a9d6c6..9b5b6ed0005 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -52,6 +52,7 @@ std_headers = \
> ${std_srcdir}/iostream \
> ${std_srcdir}/istream \
> ${std_srcdir}/iterator \
>+ ${std_srcdir}/latch \
> ${std_srcdir}/limits \
> ${std_srcdir}/list \
> ${std_srcdir}/locale \
>@@ -69,6 +70,7 @@ std_headers = \
> ${std_srcdir}/ratio \
> ${std_srcdir}/regex \
> ${std_srcdir}/scoped_allocator \
>+ ${std_srcdir}/semaphore \
> ${std_srcdir}/set \
> ${std_srcdir}/shared_mutex \
> ${std_srcdir}/span \
>@@ -101,6 +103,8 @@ bits_headers = \
> ${bits_srcdir}/allocated_ptr.h \
> ${bits_srcdir}/allocator.h \
> ${bits_srcdir}/atomic_base.h \
>+ ${bits_srcdir}/atomic_wait.h \
>+ ${bits_srcdir}/atomic_timed_wait.h \
> ${bits_srcdir}/atomic_futex.h \
> ${bits_srcdir}/basic_ios.h \
> ${bits_srcdir}/basic_ios.tcc \
>@@ -175,6 +179,7 @@ bits_headers = \
> ${bits_srcdir}/regex_compiler.tcc \
> ${bits_srcdir}/regex_executor.h \
> ${bits_srcdir}/regex_executor.tcc \
>+ ${bits_srcdir}/semaphore_base.h \
> ${bits_srcdir}/shared_ptr.h \
> ${bits_srcdir}/shared_ptr_atomic.h \
> ${bits_srcdir}/shared_ptr_base.h \
>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>index 2cdd2bd6cae..dd4db926592 100644
>--- a/libstdc++-v3/include/bits/atomic_base.h
>+++ b/libstdc++-v3/include/bits/atomic_base.h
>@@ -37,6 +37,10 @@
> #include <bits/atomic_lockfree_defines.h>
> #include <bits/move.h>
>
>+#if __cplusplus > 201703L
>+#include <bits/atomic_wait.h>
>+#endif
>+
> #ifndef _GLIBCXX_ALWAYS_INLINE
> #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
> #endif
>@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> return __ret;
> }
>
>-
> // Base types for atomics.
> template<typename _IntTp>
> struct __atomic_base;
>@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __atomic_load(&_M_i, &__v, int(__m));
> return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
> }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(bool __old,
>+ memory_order __m = memory_order_seq_cst) const noexcept
>+ {
>+ std::__atomic_wait(&_M_i, __old,
>+ [__m, this, __old]()
>+ { return this->test(__m) != __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { std::__atomic_notify(&_M_i, false); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { std::__atomic_notify(&_M_i, true); }
>+
>+ // TODO add const volatile overload
> #endif // C++20
>
> _GLIBCXX_ALWAYS_INLINE void
>@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__m));
> }
>
>+#if __cplusplus > 201703L
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(__int_type __old,
>+ memory_order __m = memory_order_seq_cst) const noexcept
>+ {
>+ std::__atomic_wait(&_M_i, __old,
>+ [__m, this, __old]
>+ { return this->load(__m) != __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { std::__atomic_notify(&_M_i, false); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { std::__atomic_notify(&_M_i, true); }
>+
>+ // TODO add const volatile overload
>+#endif // C++2a
>+
> _GLIBCXX_ALWAYS_INLINE __int_type
> fetch_add(__int_type __i,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> int(__m1), int(__m2));
> }
>
>+#if __cplusplus > 201703L
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(__pointer_type __old,
>+ memory_order __m = memory_order_seq_cst) noexcept
>+ {
>+ std::__atomic_wait(&_M_p, __old,
>+ [__m, this, __old]()
>+ { return this->load(__m) != __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { std::__atomic_notify(&_M_p, false); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { std::__atomic_notify(&_M_p, true); }
>+
>+ // TODO add const volatile overload
>+#endif // C++2a
>+
> _GLIBCXX_ALWAYS_INLINE __pointer_type
> fetch_add(ptrdiff_t __d,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> int(__success), int(__failure));
> }
>
>+#if __cplusplus > 201703L
>+ template<typename _Tp>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(const _Tp* __ptr, _Val<_Tp> __old,
>+ memory_order __m = memory_order_seq_cst) noexcept
>+ {
>+ std::__atomic_wait(__ptr, __old,
>+ [=]() { return load(__ptr, __m) == __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ template<typename _Tp>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one(const _Tp* __ptr) noexcept
>+ { std::__atomic_notify(__ptr, false); }
>+
>+ // TODO add const volatile overload
>+
>+ template<typename _Tp>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all(const _Tp* __ptr) noexcept
>+ { std::__atomic_notify(__ptr, true); }
>+
>+ // TODO add const volatile overload
>+#endif // C++2a
>+
> template<typename _Tp>
> _GLIBCXX_ALWAYS_INLINE _Tp
> fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
>@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(&_M_fp, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(&_M_fp); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(&_M_fp); }
>+
>+ // TODO add const volatile overload
>+
> value_type
> fetch_add(value_type __i,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> private:
> _Tp* _M_ptr;
> };
>@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> value_type
> fetch_add(value_type __i,
> memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> value_type
> fetch_add(value_type __i,
> memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> _GLIBCXX_ALWAYS_INLINE value_type
> fetch_add(difference_type __d,
> memory_order __m = memory_order_seq_cst) const noexcept
>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>new file mode 100644
>index 00000000000..2f57356b366
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>@@ -0,0 +1,281 @@
>+// -*- C++ -*- header.
>+
>+// 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/atomic_timed_wait.h
>+ * This is an internal header file, included by other library headers.
>+ * Do not attempt to use it directly. @headername{atomic}
>+ */
>+
>+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
>+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/functional_hash.h>
>+#include <bits/atomic_wait.h>
>+
>+#include <chrono>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <sys/time.h>
>+#endif
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+ enum class __atomic_wait_status { no_timeout, timeout };
>+
>+ namespace __detail
>+ {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ using __platform_wait_clock_t = chrono::steady_clock;
>+
>+ template<typename _Duration>
>+ __atomic_wait_status
>+ __platform_wait_until_impl(__platform_wait_t* __addr,
>+ __platform_wait_t __val,
>+ const chrono::time_point<__platform_wait_clock_t,
>+ _Duration>& __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())
>+ };
>+
>+ auto __e = syscall (SYS_futex, __addr,
>+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>+ __val, &__rt, nullptr,
>+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
>+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>+ std::terminate();
>+ return (__platform_wait_clock_t::now() < __atime)
>+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>+ }
>+
>+ template<typename _Clock, typename _Duration>
>+ __atomic_wait_status
>+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>+ const chrono::time_point<_Clock, _Duration>& __atime)
>+ {
>+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
This case is impossible, since the other overload would be selected
if the clock is the __platform_wait_clock_t (unless the caller says
__platform_wait_until<__platform_wait_until> to explicitly call this
overload, but users can't call this function, and we won't do that).
>+ {
>+ return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
>+ }
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-09-11 23:58 ` [PATCH] libstdc++: " Thomas Rodgers
2020-09-28 13:25 ` Jonathan Wakely
@ 2020-09-28 13:30 ` Jonathan Wakely
2020-09-28 13:36 ` Jonathan Wakely
2 siblings, 0 replies; 35+ messages in thread
From: Jonathan Wakely @ 2020-09-28 13:30 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers
On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This patch supercedes both the Add C++2a synchronization support patch
>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>
>Add support for -
> * atomic_flag::wait/notify_one/notify_all
> * atomic::wait/notify_one/notify_all
> * counting_semaphore
> * binary_semaphore
> * latch
>
>libstdc++-v3/ChangeLog:
>
> * include/Makefile.am (bits_headers): Add new header.
> * include/Makefile.in: Regenerate.
> * include/bits/atomic_base.h (__atomic_flag::wait): Define.
> (__atomic_flag::notify_one): Likewise.
> (__atomic_flag::notify_all): Likewise.
> (__atomic_base<_Itp>::wait): Likewise.
> (__atomic_base<_Itp>::notify_one): Likewise.
> (__atomic_base<_Itp>::notify_all): Likewise.
> (__atomic_base<_Ptp*>::wait): Likewise.
> (__atomic_base<_Ptp*>::notify_one): Likewise.
> (__atomic_base<_Ptp*>::notify_all): Likewise.
> (__atomic_impl::wait): Likewise.
> (__atomic_impl::notify_one): Likewise.
> (__atomic_impl::notify_all): Likewise.
> (__atomic_float<_Fp>::wait): Likewise.
> (__atomic_float<_Fp>::notify_one): Likewise.
> (__atomic_float<_Fp>::notify_all): Likewise.
> (__atomic_ref<_Tp>::wait): Likewise.
> (__atomic_ref<_Tp>::notify_one): Likewise.
> (__atomic_ref<_Tp>::notify_all): Likewise.
> (atomic_wait<_Tp>): Likewise.
> (atomic_wait_explicit<_Tp>): Likewise.
> (atomic_notify_one<_Tp>): Likewise.
> (atomic_notify_all<_Tp>): Likewise.
> * include/bits/atomic_wait.h: New file.
> * include/bits/atomic_timed_wait.h: New file.
> * include/bits/semaphore_base.h: New file.
> * include/std/atomic (atomic<bool>::wait): Define.
> (atomic<bool>::wait_one): Likewise.
> (atomic<bool>::wait_all): Likewise.
> (atomic<_Tp>::wait): Likewise.
> (atomic<_Tp>::wait_one): Likewise.
> (atomic<_Tp>::wait_all): Likewise.
> (atomic<_Tp*>::wait): Likewise.
> (atomic<_Tp*>::wait_one): Likewise.
> (atomic<_Tp*>::wait_all): Likewise.
> * include/std/latch: New file.
> * include/std/semaphore: New file.
> * include/std/version: Add __cpp_lib_semaphore and
> __cpp_lib_latch defines.
> * testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
> * testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
> * testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
> * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
> * testsuite/30_thread/semaphore/1.cc: New test.
> * testsuite/30_thread/semaphore/2.cc: Likewise.
> * testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
> * testsuite/30_thread/latch/1.cc: New test.
> * testsuite/30_thread/latch/2.cc: New test.
> * testsuite/30_thread/latch/3.cc: New test.
>---
> libstdc++-v3/include/Makefile.am | 5 +
> libstdc++-v3/include/Makefile.in | 5 +
> libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
> libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
> libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
> libstdc++-v3/include/std/atomic | 73 +++++
> libstdc++-v3/include/std/latch | 90 ++++++
> libstdc++-v3/include/std/semaphore | 92 ++++++
> libstdc++-v3/include/std/version | 2 +
> .../atomic/wait_notify/atomic_refs.cc | 103 ++++++
> .../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
> .../29_atomics/atomic/wait_notify/floats.cc | 32 ++
> .../29_atomics/atomic/wait_notify/generic.cc | 31 ++
> .../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
> .../atomic/wait_notify/integrals.cc | 65 ++++
> .../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
> .../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
> libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
> libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
> libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
> .../testsuite/30_threads/semaphore/1.cc | 27 ++
> .../testsuite/30_threads/semaphore/2.cc | 27 ++
> .../semaphore/least_max_value_neg.cc | 30 ++
> .../30_threads/semaphore/try_acquire.cc | 55 ++++
> .../30_threads/semaphore/try_acquire_for.cc | 85 +++++
> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
> .../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
> 28 files changed, 2471 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
> create mode 100644 libstdc++-v3/include/std/latch
> create mode 100644 libstdc++-v3/include/std/semaphore
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index c9df9a9d6c6..9b5b6ed0005 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -52,6 +52,7 @@ std_headers = \
> ${std_srcdir}/iostream \
> ${std_srcdir}/istream \
> ${std_srcdir}/iterator \
>+ ${std_srcdir}/latch \
> ${std_srcdir}/limits \
> ${std_srcdir}/list \
> ${std_srcdir}/locale \
>@@ -69,6 +70,7 @@ std_headers = \
> ${std_srcdir}/ratio \
> ${std_srcdir}/regex \
> ${std_srcdir}/scoped_allocator \
>+ ${std_srcdir}/semaphore \
> ${std_srcdir}/set \
> ${std_srcdir}/shared_mutex \
> ${std_srcdir}/span \
>@@ -101,6 +103,8 @@ bits_headers = \
> ${bits_srcdir}/allocated_ptr.h \
> ${bits_srcdir}/allocator.h \
> ${bits_srcdir}/atomic_base.h \
>+ ${bits_srcdir}/atomic_wait.h \
>+ ${bits_srcdir}/atomic_timed_wait.h \
> ${bits_srcdir}/atomic_futex.h \
These should be kept in alphabetical order.
> ${bits_srcdir}/basic_ios.h \
> ${bits_srcdir}/basic_ios.tcc \
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] libstdc++: Add C++2a synchronization support
2020-09-11 23:58 ` [PATCH] libstdc++: " Thomas Rodgers
@ 2020-09-28 13:25 ` Jonathan Wakely
2020-10-01 23:37 ` Thomas Rodgers
2020-09-28 13:30 ` Jonathan Wakely
2020-09-28 13:36 ` Jonathan Wakely
2 siblings, 1 reply; 35+ messages in thread
From: Jonathan Wakely @ 2020-09-28 13:25 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers
On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This patch supercedes both the Add C++2a synchronization support patch
>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>
>Add support for -
> * atomic_flag::wait/notify_one/notify_all
> * atomic::wait/notify_one/notify_all
> * counting_semaphore
> * binary_semaphore
> * latch
>
>libstdc++-v3/ChangeLog:
>
> * include/Makefile.am (bits_headers): Add new header.
> * include/Makefile.in: Regenerate.
> * include/bits/atomic_base.h (__atomic_flag::wait): Define.
> (__atomic_flag::notify_one): Likewise.
> (__atomic_flag::notify_all): Likewise.
> (__atomic_base<_Itp>::wait): Likewise.
> (__atomic_base<_Itp>::notify_one): Likewise.
> (__atomic_base<_Itp>::notify_all): Likewise.
> (__atomic_base<_Ptp*>::wait): Likewise.
> (__atomic_base<_Ptp*>::notify_one): Likewise.
> (__atomic_base<_Ptp*>::notify_all): Likewise.
> (__atomic_impl::wait): Likewise.
> (__atomic_impl::notify_one): Likewise.
> (__atomic_impl::notify_all): Likewise.
> (__atomic_float<_Fp>::wait): Likewise.
> (__atomic_float<_Fp>::notify_one): Likewise.
> (__atomic_float<_Fp>::notify_all): Likewise.
> (__atomic_ref<_Tp>::wait): Likewise.
> (__atomic_ref<_Tp>::notify_one): Likewise.
> (__atomic_ref<_Tp>::notify_all): Likewise.
> (atomic_wait<_Tp>): Likewise.
> (atomic_wait_explicit<_Tp>): Likewise.
> (atomic_notify_one<_Tp>): Likewise.
> (atomic_notify_all<_Tp>): Likewise.
> * include/bits/atomic_wait.h: New file.
> * include/bits/atomic_timed_wait.h: New file.
> * include/bits/semaphore_base.h: New file.
> * include/std/atomic (atomic<bool>::wait): Define.
> (atomic<bool>::wait_one): Likewise.
> (atomic<bool>::wait_all): Likewise.
> (atomic<_Tp>::wait): Likewise.
> (atomic<_Tp>::wait_one): Likewise.
> (atomic<_Tp>::wait_all): Likewise.
> (atomic<_Tp*>::wait): Likewise.
> (atomic<_Tp*>::wait_one): Likewise.
> (atomic<_Tp*>::wait_all): Likewise.
> * include/std/latch: New file.
> * include/std/semaphore: New file.
> * include/std/version: Add __cpp_lib_semaphore and
> __cpp_lib_latch defines.
> * testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
> * testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
> * testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
> * testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
> * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
> * testsuite/30_thread/semaphore/1.cc: New test.
> * testsuite/30_thread/semaphore/2.cc: Likewise.
> * testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
> * testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
> * testsuite/30_thread/latch/1.cc: New test.
> * testsuite/30_thread/latch/2.cc: New test.
> * testsuite/30_thread/latch/3.cc: New test.
>---
> libstdc++-v3/include/Makefile.am | 5 +
> libstdc++-v3/include/Makefile.in | 5 +
> libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
> libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
> libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
> libstdc++-v3/include/std/atomic | 73 +++++
> libstdc++-v3/include/std/latch | 90 ++++++
> libstdc++-v3/include/std/semaphore | 92 ++++++
> libstdc++-v3/include/std/version | 2 +
> .../atomic/wait_notify/atomic_refs.cc | 103 ++++++
> .../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
> .../29_atomics/atomic/wait_notify/floats.cc | 32 ++
> .../29_atomics/atomic/wait_notify/generic.cc | 31 ++
> .../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
> .../atomic/wait_notify/integrals.cc | 65 ++++
> .../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
> .../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
> libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
> libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
> libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
> .../testsuite/30_threads/semaphore/1.cc | 27 ++
> .../testsuite/30_threads/semaphore/2.cc | 27 ++
> .../semaphore/least_max_value_neg.cc | 30 ++
> .../30_threads/semaphore/try_acquire.cc | 55 ++++
> .../30_threads/semaphore/try_acquire_for.cc | 85 +++++
> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
> .../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
> 28 files changed, 2471 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
> create mode 100644 libstdc++-v3/include/std/latch
> create mode 100644 libstdc++-v3/include/std/semaphore
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index c9df9a9d6c6..9b5b6ed0005 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -52,6 +52,7 @@ std_headers = \
> ${std_srcdir}/iostream \
> ${std_srcdir}/istream \
> ${std_srcdir}/iterator \
>+ ${std_srcdir}/latch \
> ${std_srcdir}/limits \
> ${std_srcdir}/list \
> ${std_srcdir}/locale \
>@@ -69,6 +70,7 @@ std_headers = \
> ${std_srcdir}/ratio \
> ${std_srcdir}/regex \
> ${std_srcdir}/scoped_allocator \
>+ ${std_srcdir}/semaphore \
> ${std_srcdir}/set \
> ${std_srcdir}/shared_mutex \
> ${std_srcdir}/span \
>@@ -101,6 +103,8 @@ bits_headers = \
> ${bits_srcdir}/allocated_ptr.h \
> ${bits_srcdir}/allocator.h \
> ${bits_srcdir}/atomic_base.h \
>+ ${bits_srcdir}/atomic_wait.h \
>+ ${bits_srcdir}/atomic_timed_wait.h \
> ${bits_srcdir}/atomic_futex.h \
> ${bits_srcdir}/basic_ios.h \
> ${bits_srcdir}/basic_ios.tcc \
>@@ -175,6 +179,7 @@ bits_headers = \
> ${bits_srcdir}/regex_compiler.tcc \
> ${bits_srcdir}/regex_executor.h \
> ${bits_srcdir}/regex_executor.tcc \
>+ ${bits_srcdir}/semaphore_base.h \
> ${bits_srcdir}/shared_ptr.h \
> ${bits_srcdir}/shared_ptr_atomic.h \
> ${bits_srcdir}/shared_ptr_base.h \
>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>index 2cdd2bd6cae..dd4db926592 100644
>--- a/libstdc++-v3/include/bits/atomic_base.h
>+++ b/libstdc++-v3/include/bits/atomic_base.h
>@@ -37,6 +37,10 @@
> #include <bits/atomic_lockfree_defines.h>
> #include <bits/move.h>
>
>+#if __cplusplus > 201703L
>+#include <bits/atomic_wait.h>
>+#endif
>+
> #ifndef _GLIBCXX_ALWAYS_INLINE
> #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
> #endif
>@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> return __ret;
> }
>
>-
> // Base types for atomics.
> template<typename _IntTp>
> struct __atomic_base;
>@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __atomic_load(&_M_i, &__v, int(__m));
> return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
> }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(bool __old,
>+ memory_order __m = memory_order_seq_cst) const noexcept
>+ {
>+ std::__atomic_wait(&_M_i, __old,
>+ [__m, this, __old]()
>+ { return this->test(__m) != __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { std::__atomic_notify(&_M_i, false); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { std::__atomic_notify(&_M_i, true); }
>+
>+ // TODO add const volatile overload
> #endif // C++20
>
> _GLIBCXX_ALWAYS_INLINE void
>@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__m));
> }
>
>+#if __cplusplus > 201703L
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(__int_type __old,
>+ memory_order __m = memory_order_seq_cst) const noexcept
>+ {
>+ std::__atomic_wait(&_M_i, __old,
>+ [__m, this, __old]
>+ { return this->load(__m) != __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { std::__atomic_notify(&_M_i, false); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { std::__atomic_notify(&_M_i, true); }
>+
>+ // TODO add const volatile overload
>+#endif // C++2a
>+
> _GLIBCXX_ALWAYS_INLINE __int_type
> fetch_add(__int_type __i,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> int(__m1), int(__m2));
> }
>
>+#if __cplusplus > 201703L
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(__pointer_type __old,
>+ memory_order __m = memory_order_seq_cst) noexcept
>+ {
>+ std::__atomic_wait(&_M_p, __old,
>+ [__m, this, __old]()
>+ { return this->load(__m) != __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { std::__atomic_notify(&_M_p, false); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { std::__atomic_notify(&_M_p, true); }
>+
>+ // TODO add const volatile overload
>+#endif // C++2a
>+
> _GLIBCXX_ALWAYS_INLINE __pointer_type
> fetch_add(ptrdiff_t __d,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> int(__success), int(__failure));
> }
>
>+#if __cplusplus > 201703L
>+ template<typename _Tp>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(const _Tp* __ptr, _Val<_Tp> __old,
>+ memory_order __m = memory_order_seq_cst) noexcept
>+ {
>+ std::__atomic_wait(__ptr, __old,
>+ [=]() { return load(__ptr, __m) == __old; });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ template<typename _Tp>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one(const _Tp* __ptr) noexcept
>+ { std::__atomic_notify(__ptr, false); }
>+
>+ // TODO add const volatile overload
>+
>+ template<typename _Tp>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all(const _Tp* __ptr) noexcept
>+ { std::__atomic_notify(__ptr, true); }
>+
>+ // TODO add const volatile overload
>+#endif // C++2a
>+
> template<typename _Tp>
> _GLIBCXX_ALWAYS_INLINE _Tp
> fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
>@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(&_M_fp, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(&_M_fp); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(&_M_fp); }
>+
>+ // TODO add const volatile overload
>+
> value_type
> fetch_add(value_type __i,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> private:
> _Tp* _M_ptr;
> };
>@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> value_type
> fetch_add(value_type __i,
> memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> value_type
> fetch_add(value_type __i,
> memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__order));
> }
>
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_one() const noexcept
>+ { __atomic_impl::notify_one(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ notify_all() const noexcept
>+ { __atomic_impl::notify_all(_M_ptr); }
>+
>+ // TODO add const volatile overload
>+
> _GLIBCXX_ALWAYS_INLINE value_type
> fetch_add(difference_type __d,
> memory_order __m = memory_order_seq_cst) const noexcept
>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>new file mode 100644
>index 00000000000..2f57356b366
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>@@ -0,0 +1,281 @@
>+// -*- C++ -*- header.
>+
>+// 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/atomic_timed_wait.h
>+ * This is an internal header file, included by other library headers.
>+ * Do not attempt to use it directly. @headername{atomic}
>+ */
>+
>+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
>+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/functional_hash.h>
>+#include <bits/atomic_wait.h>
>+
>+#include <chrono>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <sys/time.h>
>+#endif
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+ enum class __atomic_wait_status { no_timeout, timeout };
>+
>+ namespace __detail
>+ {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ using __platform_wait_clock_t = chrono::steady_clock;
>+
>+ template<typename _Duration>
>+ __atomic_wait_status
>+ __platform_wait_until_impl(__platform_wait_t* __addr,
>+ __platform_wait_t __val,
>+ const chrono::time_point<__platform_wait_clock_t,
>+ _Duration>& __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())
>+ };
>+
>+ auto __e = syscall (SYS_futex, __addr,
>+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>+ __val, &__rt, nullptr,
>+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
>+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>+ std::terminate();
>+ return (__platform_wait_clock_t::now() < __atime)
>+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
Newline before the ': __atomic_wait_status::timeout' to keep it
fitting in 80 columns.
>+ }
>+
>+ template<typename _Clock, typename _Duration>
>+ __atomic_wait_status
>+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>+ const chrono::time_point<_Clock, _Duration>& __atime)
>+ {
>+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
>+ {
>+ return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
I askjed for this to be qualified, but just __detail:: is enough, you
don't need std::__detail. That should make the line fit in 80 columns.
There are still dozens of lines that don't fit in 80 cols in this
revision of the patch.
>+ }
>+ else
>+ {
>+ const typename _Clock::time_point __c_entry = _Clock::now();
>+ const __platform_wait_clock_t::time_point __s_entry =
>+ __platform_wait_clock_t::now();
>+ const auto __delta = __atime - __c_entry;
>+ const auto __s_atime = __s_entry + __delta;
>+ if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
Just __detail:: again for the qualification. It doesn't need to be
std::__detail::.
Line breaks should be before operators please, i.e.
value_with_a_long_name
== bar
or:
long_condition
&& another_condition
It's much easier to find the operator when it's at the start of the
line, at a predictable indentation, rather than wandering off on the
right somewhere.
>+ __atomic_wait_status::no_timeout)
>+ return __atomic_wait_status::no_timeout;
>+
>+ // We got a timeout when measured against __clock_t but
>+ // we need to check against the caller-supplied clock
>+ // to tell whether we should return a timeout.
>+ if (_Clock::now() < __atime)
>+ return __atomic_wait_status::no_timeout;
>+ return __atomic_wait_status::timeout;
>+ }
>+ }
>+#endif
>+
>+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
>+ template<typename _Duration>
>+ __atomic_wait_status
>+ __cond_wait_until_impl(__gthread_cond_t* __cv,
>+ unique_lock<mutex>& __lock,
>+ 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())
>+ };
>+
>+ pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
>+ CLOCK_MONOTONIC,
>+ &__ts);
>+ return (chrono::steady_clock::now() < __atime)
>+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>+ }
>+#endif
>+
>+ template<typename _Duration>
>+ __atomic_wait_status
>+ __cond_wait_until_impl(__gthread_cond_t* __cv,
>+ unique_lock<std::mutex>& __lock,
>+ 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_cond_timedwait(__cv, __lock.mutex()->native_handle(),
>+ &__ts);
>+ return (chrono::system_clock::now() < __atime)
>+ ? __atomic_wait_status::no_timeout
>+ : __atomic_wait_status::timeout;
>+ }
>+
>+ // return true if timeout
>+ template<typename _Clock, typename _Duration>
>+ __atomic_wait_status
>+ __cond_wait_until(__gthread_cond_t* __cv,
>+ unique_lock<std::mutex>& __lock,
>+ const chrono::time_point<_Clock, _Duration>& __atime)
>+ {
>+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
>+ using __clock_t = chrono::steady_clock;
>+#else
>+ using __clock_t = chrono::system_clock;
>+#endif
>+ const typename _Clock::time_point __c_entry = _Clock::now();
>+ const __clock_t::time_point __s_entry = __clock_t::now();
>+ const auto __delta = __atime - __c_entry;
>+ const auto __s_atime = __s_entry + __delta;
>+ if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
>+ return __atomic_wait_status::no_timeout;
>+ // We got a timeout when measured against __clock_t but
>+ // we need to check against the caller-supplied clock
>+ // to tell whether we should return a timeout.
>+ if (_Clock::now() < __atime)
>+ return __atomic_wait_status::no_timeout;
>+ return __atomic_wait_status::timeout;
>+ }
>+
>+ struct __timed_waiters : __waiters
>+ {
>+ template<typename _Clock, typename _Duration>
>+ __atomic_wait_status
>+ _M_do_wait_until(__platform_wait_t __version,
>+ const chrono::time_point<_Clock, _Duration>& __atime)
>+ {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ return __platform_wait_until(&_M_ver, __version, __atime);
>+#else
>+ __platform_wait_t __cur = 0;
>+ __waiters::__lock_t __l(_M_mtx);
>+ while (__cur <= __version)
>+ {
>+ if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
>+ __atomic_wait_status::timeout)
>+ return __atomic_wait_status::timeout;
>+
>+ __platform_wait_t __last = __cur;
>+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
>+ if (__cur < __last)
>+ break; // break the loop if version overflows
>+ }
>+ return __atomic_wait_status::no_timeout;
>+#endif
>+ }
>+
>+ static __timed_waiters&
>+ _S_timed_for(void* __t)
>+ {
>+ static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
>+ return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
>+ }
>+ };
>+ } // namespace __detail
>+
>+ template<typename _Tp, typename _Pred,
>+ typename _Clock, typename _Duration>
>+ bool
>+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
>+ const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+ {
>+ using namespace __detail;
>+
>+ if (std::__atomic_spin(__pred))
>+ return true;
>+
>+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
>+ auto __version = __w._M_enter_wait();
>+ do
>+ {
>+ __atomic_wait_status __res;
>+ if constexpr (__platform_wait_uses_type<_Tp>)
>+ {
>+ __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
>+ __old,
>+ __atime);
>+ }
>+ else
>+ {
>+ __res = __w._M_do_wait_until(__version, __atime);
>+ }
>+ if (__res == __atomic_wait_status::timeout)
>+ return false;
>+ }
>+ while (!__pred() && __atime < _Clock::now());
>+ __w._M_leave_wait();
>+
>+ // if timed out, return false
>+ return (_Clock::now() < __atime);
>+ }
>+
>+ template<typename _Tp, typename _Pred,
>+ typename _Rep, typename _Period>
>+ bool
>+ __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
>+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+ {
>+ using namespace __detail;
>+
>+ if (std::__atomic_spin(__pred))
>+ return true;
>+
>+ if (!__rtime.count())
>+ return false; // no rtime supplied, and spin did not acquire
>+
>+ using __dur = chrono::steady_clock::duration;
>+ auto __reltime = chrono::duration_cast<__dur>(__rtime);
>+ if (__reltime < __rtime)
>+ ++__reltime;
>+
>+
>+ return __atomic_wait_until(__addr, __old, std::move(__pred),
>+ chrono::steady_clock::now() + __reltime);
>+ }
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+#endif
>diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
>new file mode 100644
>index 00000000000..21ec3d38c94
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>@@ -0,0 +1,301 @@
>+// -*- C++ -*- header.
>+
>+// 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/atomic_wait.h
>+ * This is an internal header file, included by other library headers.
>+ * Do not attempt to use it directly. @headername{atomic}
>+ */
>+
>+#ifndef _GLIBCXX_ATOMIC_WAIT_H
>+#define _GLIBCXX_ATOMIC_WAIT_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/functional_hash.h>
>+#include <bits/gthr.h>
>+#include <bits/std_mutex.h>
>+#include <bits/unique_lock.h>
>+#include <ext/numeric_traits.h>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <climits>
>+#include <unistd.h>
>+#include <syscall.h>
>+#endif
>+
>+
>+// TODO get this from Autoconf
>+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+ namespace __detail
>+ {
>+ using __platform_wait_t = int;
>+
>+ constexpr auto __atomic_spin_count_1 = 16;
>+ constexpr auto __atomic_spin_count_2 = 12;
>+
>+ inline constexpr
>+ auto __platform_wait_max_value =
>+ __gnu_cxx::__int_traits<__platform_wait_t>::__max;
>+
>+ template<typename _Tp>
>+ inline constexpr bool __platform_wait_uses_type
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ = is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
>+#else
>+ = false;
>+#endif
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ enum class __futex_wait_flags : int
>+ {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>+ __private_flag = 128,
>+#else
>+ __private_flag = 0,
>+#endif
>+ __wait = 0,
>+ __wake = 1,
>+ __wait_bitset = 9,
>+ __wake_bitset = 10,
>+ __wait_private = __wait | __private_flag,
>+ __wake_private = __wake | __private_flag,
>+ __wait_bitset_private = __wait_bitset | __private_flag,
>+ __wake_bitset_private = __wake_bitset | __private_flag,
>+ __bitset_match_any = -1
>+ };
>+
>+ template<typename _Tp>
>+ void
>+ __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
>+ {
>+ auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
>+ static_cast<int>(__futex_wait_flags::__wait_private),
>+ __val, nullptr);
>+ if (__e && !(errno == EINTR || errno == EAGAIN))
>+ std::terminate();
This treats EINTR and EGAIN as a spurious wakeup, right?
So callers cannot assume that this function has actually waited for
the value to change. I'll come back to that below.
>+ struct __waiters
>+ {
>+ __platform_wait_t alignas(64) _M_ver = 0;
>+ __platform_wait_t alignas(64) _M_wait = 0;
The alignment-specifier needs to come before the type name:
a.cc:3:7: warning: attribute ignored [-Wattributes]
3 | int alignas(64) i = 0;
| ^~~~~~~
a.cc:3:7: note: an attribute that appertains to a type-specifier is ignored
>+ __platform_wait_t
>+ _M_waiting() const noexcept
Should this function return a bool?
It looks like the only caller of it just tests if it's zero.
If it means "number of waiters" rather than "there are threads
waiting" then I think it should be renamed to make that more clear
(and similarly for _M_wait, which sounds like a boolean flag not a
count).
>+ {
>+ __platform_wait_t __res;
>+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
>+ return __res;
>+ }
>+
>+ void
>+ _M_notify(bool __all) noexcept
>+ {
>+ __atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ __platform_notify(&_M_ver, __all);
>+#else
>+ auto __e = __gthread_cond_broadcast(&_M_cv);
>+ if (__e)
>+ __throw_system_error(__e);
This will terminate since the function is noexcept, which is fine.
Maybe we should consistently use __throw_system_error(__e) which
allows the verbose terminate handler to print a message:
terminate called after throwing an instance of 'std::system_error'
what(): Resource temporarily unavailable
Aborted (core dumped)
So the other places that currently call std::terminate() should maybe
change to __throw_system_error(__e). What do you think?
>+#endif
>+ }
>+
>+ static __waiters&
>+ _S_for(const void* __t)
>+ {
>+ const unsigned char __mask = 0xf;
>+ static __waiters __w[__mask + 1];
>+
>+ auto __key = _Hash_impl::hash(__t) & __mask;
>+ return __w[__key];
>+ }
>+ };
>+
>+ struct __waiter
>+ {
>+ __waiters& _M_w;
>+ __platform_wait_t _M_version;
>+
>+ template<typename _Tp>
>+ __waiter(const _Tp* __addr) noexcept
>+ : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
>+ , _M_version(_M_w._M_enter_wait())
>+ { }
>+
>+ ~__waiter()
>+ { _M_w._M_leave_wait(); }
>+
>+ void _M_do_wait() noexcept
>+ { _M_w._M_do_wait(_M_version); }
>+ };
>+
>+ void
>+ __thread_relax() noexcept
>+ {
>+#if defined __i386__ || defined __x86_64__
>+ __builtin_ia32_pause();
>+#elif defined _GLIBCXX_USE_SCHED_YIELD
>+ __gthread_yield();
>+#endif
>+ }
>+
>+ void
>+ __thread_yield() noexcept
>+ {
>+#if defined _GLIBCXX_USE_SCHED_YIELD
>+ __gthread_yield();
>+#endif
>+ }
>+
>+ } // namespace __detail
>+
>+ template<typename _Pred>
>+ bool
>+ __atomic_spin(_Pred __pred) noexcept
Should this take its argument by (non-const) reference?
>+ {
>+ for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
>+ {
>+ if (__pred())
>+ return true;
>+
>+ if (__i < __detail::__atomic_spin_count_2)
>+ __detail::__thread_relax();
>+ else
>+ __detail::__thread_yield();
>+ }
>+ return false;
>+ }
>+
>+ template<typename _Tp, typename _Pred>
>+ void
>+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
>+ {
>+ using namespace __detail;
>+ if (__atomic_spin(__pred))
>+ return;
>+
>+ __waiter __w(__addr);
>+ while (!__pred())
>+ {
>+ if constexpr (__platform_wait_uses_type<_Tp>)
>+ {
>+ __platform_wait(__addr, __old);
If this gets a spurious wakeup due to EINTR or EAGAIN then we'll loop
and test the predicate again.
>+ }
>+ else
>+ {
>+ // TODO support timed backoff when this can be moved into the lib
>+ __w._M_do_wait();
>+ }
>+ }
>+ }
>+
>+ template<typename _Tp>
>+ void
>+ __atomic_notify(const _Tp* __addr, bool __all) noexcept
>+ {
>+ using namespace __detail;
>+ auto& __w = __waiters::_S_for((void*)__addr);
>+ if (!__w._M_waiting())
>+ return;
>+
>+ if constexpr (__platform_wait_uses_type<_Tp>)
>+ {
>+ __platform_notify((__platform_wait_t*)(void*) __addr, __all);
>+ }
>+ else
>+ {
>+ __w._M_notify(__all);
>+ }
>+ }
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+#endif
>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>new file mode 100644
>index 00000000000..ed127a7a953
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>@@ -0,0 +1,283 @@
>+// -*- C++ -*- header.
>+
>+// 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/semaphore_base.h
>+ * This is an internal header file, included by other library headers.
>+ * Do not attempt to use it directly. @headername{semaphore}
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
>+#define _GLIBCXX_SEMAPHORE_BASE_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/atomic_base.h>
>+#include <bits/atomic_timed_wait.h>
>+
>+#if __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
>+#endif
>+
>+#include <chrono>
>+#include <type_traits>
>+
>+#include <iostream>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+ struct __platform_semaphore
>+ {
>+ using __clock_t = chrono::system_clock;
>+ static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
>+
>+ explicit __platform_semaphore(ptrdiff_t __count) noexcept
>+ {
>+ sem_init(&_M_semaphore, 0, __count);
>+ }
>+
>+ __platform_semaphore(const __platform_semaphore&) = delete;
>+ __platform_semaphore& operator=(const __platform_semaphore&) = delete;
>+
>+ ~__platform_semaphore()
>+ { sem_destroy(&_M_semaphore); }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_acquire() noexcept
>+ {
>+ for (;;)
>+ {
>+ auto __err = sem_wait(&_M_semaphore);
>+ if (__err && (errno == EINTR))
>+ continue;
>+ else if (__err)
>+ std::terminate();
>+ else
>+ break;
>+ }
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_release(std::ptrdiff_t __update) noexcept
>+ {
>+ for(; __update != 0; --__update)
>+ {
>+ auto __err = sem_post(&_M_semaphore);
>+ if (__err)
>+ std::terminate();
>+ }
>+ }
>+
>+ bool
>+ _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
>+ {
>+
>+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+ struct timespec __ts =
>+ {
>+ static_cast<std::time_t>(__s.time_since_epoch().count()),
>+ static_cast<long>(__ns.count())
>+ };
>+
>+ for (;;)
>+ {
>+ auto __err = sem_timedwait(&_M_semaphore, &__ts);
>+ if (__err && (errno == EINTR))
>+ continue;
>+ else if (__err && (errno == ETIMEDOUT))
>+ return false;
>+ else if (__err && (errno == EINVAL))
>+ return false; // caller supplied an invalid __atime
>+ else if (__err)
>+ std::terminate();
>+ else
>+ break;
>+ }
>+ return true;
>+ }
>+
>+ template<typename _Clock, typename _Duration>
>+ bool
>+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+ {
>+ if constexpr (std::is_same<__clock_t, _Clock>::value)
>+ {
>+ return _M_try_acquire_until_impl(__atime);
>+ }
>+ else
>+ {
>+ const typename _Clock::time_point __c_entry = _Clock::now();
>+ const __clock_t __s_entry = __clock_t::now();
>+ const auto __delta = __atime - __c_entry;
>+ const auto __s_atime = __s_entry + __delta;
>+ if (_M_try_acquire_until_impl(__s_atime))
>+ return true;
>+
>+ // We got a timeout when measured against __clock_t but
>+ // we need to check against the caller-supplied clock
>+ // to tell whether we should return a timeout.
>+ return (_Clock::now() < __atime);
>+ }
>+ }
>+
>+ template<typename _Rep, typename _Period>
>+ _GLIBCXX_ALWAYS_INLINE bool
>+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+ { return _M_try_acquire_until(__clock_t::now() + __rtime); }
>+
>+ private:
>+ sem_t _M_semaphore;
>+ };
>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+
>+ template<typename _Tp>
>+ struct __atomic_semaphore
>+ {
>+ static_assert(std::is_integral_v<_Tp>);
>+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
Do we need a check that ptrdiff_t can represent this value?
__atomic_semaphore<size_t> would overflow here.
>+
>+ explicit __atomic_semaphore(_Tp __count) noexcept
>+ : _M_a(__count)
>+ { }
This should use __glibcxx_assert to check the preconditions:
__glibcxx_assert(__count >= 0 && __count <= max());
>+
>+ __atomic_semaphore(const __atomic_semaphore&) = delete;
>+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_acquire() noexcept
>+ {
>+ auto const __pred = [this]
>+ {
>+ auto __old = __atomic_impl::load(&this->_M_a,
>+ memory_order::acquire);
>+ if (__old == 0)
>+ return false;
>+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
>+ __old, __old - 1,
>+ memory_order::acquire,
>+ memory_order::release);
>+ };
>+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+ __atomic_wait(&_M_a, __old, __pred);
>+ }
>+
>+ bool
>+ _M_try_acquire() noexcept
>+ {
>+ auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
>+ if (__old == 0)
>+ return false;
>+
>+ return __atomic_spin([this, &__old]
>+ {
Doesn't the check for __old==0 need to be inside the predicate?
Otherwise consider the case where _M_a=1 initially. Two threads call
try_acquire() concurrently. Both see that __old==0 is false, so both
call __atomic_spin with this CAS "predicate" (*). The first thread
replaces the value with 0, the second thread fails the CAS because the
value changed, but it replaces __old with the new value and tries
again (because __atomic_spin loops) and this time it succeeds,
changing the value to -1. The second thread should have had no effect
and returned immediately.
(*) I find it a bit disconcerting that these predicates are not const,
they modify the variable, which implies a precondition that the
predicate is never evaluated again after it returns true.
>+ return __atomic_impl::compare_exchange_weak(&this->_M_a,
>+ __old, __old - 1,
>+ memory_order::acquire,
>+ memory_order::release);
>+ });
>+ }
>+
>+ template<typename _Clock, typename _Duration>
>+ _GLIBCXX_ALWAYS_INLINE bool
>+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+ {
>+ auto const __pred = [this]
>+ {
>+ auto __old = __atomic_impl::load(&this->_M_a,
>+ memory_order::acquire);
>+ if (__old == 0)
>+ return false;
>+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
>+ __old, __old - 1,
>+ memory_order::acquire,
>+ memory_order::release);
>+ };
>+
>+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+ return __atomic_wait_until(&_M_a, __old, __pred, __atime);
>+ }
>+
>+ template<typename _Rep, typename _Period>
>+ _GLIBCXX_ALWAYS_INLINE bool
>+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+ {
>+ auto const __pred = [this]
>+ {
>+ auto __old = __atomic_impl::load(&this->_M_a,
>+ memory_order::acquire);
>+ if (__old == 0)
>+ return false;
>+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
>+ __old, __old - 1,
>+ memory_order::acquire,
>+ memory_order::release);
>+ };
>+
>+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+ return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_release(ptrdiff_t __update) noexcept
>+ {
>+ if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
>+ return;
>+ if (__update > 1)
>+ __atomic_impl::notify_all(&_M_a);
>+ else
>+ __atomic_impl::notify_one(&_M_a);
>+ }
>+
>+ private:
>+ alignas(__alignof__(_Tp)) _Tp _M_a;
I'd prefer a better name than _M_a here.
The standard calls it "counter" so _M_counter maybe?
>+ };
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
I still don't like this macro, but nevermind.
Could you add a comment saying that the macro can be used to force the
use of POSIX sem_t but that doing so alters the ABI?
>+ // Use futex if available and didn't force use of POSIX
>+ using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
>+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+ using __fast_semaphore = __platform_semaphore;
>+#else
>+ using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
>+#endif
>+
>+template<ptrdiff_t __least_max_value>
>+ using __semaphore_impl = conditional_t<
>+ (__least_max_value > 1),
>+ conditional_t<
>+ (__least_max_value <= __fast_semaphore::_S_max),
>+ __fast_semaphore,
>+ __atomic_semaphore<ptrdiff_t>>,
>+ __fast_semaphore>;
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+
>+#endif
>diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>index 1a304261fe7..c15909d9ccb 100644
>--- a/libstdc++-v3/include/std/atomic
>+++ b/libstdc++-v3/include/std/atomic
>@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> compare_exchange_strong(bool& __i1, bool __i2,
> memory_order __m = memory_order_seq_cst) volatile noexcept
> { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
>+
>+#if __cplusplus > 201703L
>+ void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ { _M_base.wait(__old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ void notify_one() const noexcept
>+ { _M_base.notify_one(); }
>+
>+ void notify_all() const noexcept
>+ { _M_base.notify_all(); }
>+#endif
> };
>
> #if __cplusplus <= 201703L
>@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> memory_order __m = memory_order_seq_cst) volatile noexcept
> { return compare_exchange_strong(__e, __i, __m,
> __cmpexch_failure_order(__m)); }
Blank line here before the next member function please.
>+#if __cplusplus > 201703L
>+ void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+ {
>+ std::__atomic_wait(&_M_i, __old,
>+ [__m, this, __old]
>+ {
>+ const auto __v = this->load(__m);
>+ // TODO make this ignore padding bits when we can do that
>+ return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
>+ });
>+ }
>+
>+ // TODO add const volatile overload
>+
>+ void notify_one() const noexcept
>+ { std::__atomic_notify(&_M_i, false); }
>+
>+ void notify_all() const noexcept
>+ { std::__atomic_notify(&_M_i, true); }
>+#endif
>+
> };
> #undef _GLIBCXX20_INIT
>
>@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> __cmpexch_failure_order(__m));
> }
>
>+#if __cplusplus > 201703L
>+ void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>+ { _M_b.wait(__old, __m); }
>+
>+ // TODO add const volatile overload
>+
>+ void notify_one() const noexcept
>+ { _M_b.notify_one(); }
>+
>+ void notify_all() const noexcept
>+ { _M_b.notify_all(); }
>+#endif
> __pointer_type
> fetch_add(ptrdiff_t __d,
> memory_order __m = memory_order_seq_cst) noexcept
>@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> memory_order_seq_cst);
> }
>
>+
>+#if __cplusplus > 201703L
>+ template<typename _Tp>
>+ inline void
>+ atomic_wait(const atomic<_Tp>* __a,
>+ typename std::atomic<_Tp>::value_type __old) noexcept
>+ { __a->wait(__old); }
>+
>+ template<typename _Tp>
>+ inline void
>+ atomic_wait_explicit(const atomic<_Tp>* __a,
>+ typename std::atomic<_Tp>::value_type __old,
>+ std::memory_order __m) noexcept
>+ { __a->wait(__old, __m); }
>+
>+ template<typename _Tp>
>+ inline void
>+ atomic_notify_one(atomic<_Tp>* __a) noexcept
>+ { __a->notify_one(); }
>+
>+ template<typename _Tp>
>+ inline void
>+ atomic_notify_all(atomic<_Tp>* __a) noexcept
>+ { __a->notify_all(); }
>+
>+#endif // C++2a
>+
> // Function templates for atomic_integral and atomic_pointer operations only.
> // Some operations (and, or, xor) are only available for atomic integrals,
> // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
>diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
>new file mode 100644
>index 00000000000..bd06db5aa7f
>--- /dev/null
>+++ b/libstdc++-v3/include/std/latch
>@@ -0,0 +1,90 @@
>+// <latch> -*- C++ -*-
>+
>+// 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/latch
>+ * This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_LATCH
>+#define _GLIBCXX_LATCH
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_latch 201907L
>+
>+#include <bits/atomic_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+ class latch
>+ {
>+ public:
>+ static constexpr ptrdiff_t
>+ max() noexcept
>+ { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
You can use __gnu_cxx::__int_traits<ptrdiff_t> here, since we already
know ptrdiff_t is an integer type and so don't need to do the
selection between __numeric_traits for integers or floats.
>+ constexpr explicit latch(ptrdiff_t __expected) noexcept
>+ : _M_a(__expected) { }
>+
>+ ~latch() = default;
>+ latch(const latch&) = delete;
>+ latch& operator=(const latch&) = delete;
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ count_down(ptrdiff_t __update = 1)
>+ {
>+ auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
This line is too long,
>+ if (__old == __update)
>+ __atomic_impl::notify_all(&_M_a);
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE bool
>+ try_wait() const noexcept
>+ { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait() const
>+ {
>+ auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
>+ __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
This function is not noexcept, but it only calls noexcept functions.
That suggests either __atomic_wait should not be noexcept, or this one
could be.
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ arrive_and_wait(ptrdiff_t __update = 1)
>+ {
>+ count_down();
This needs to pass the __udpate parameter to count_down.
This suggests we're missing a test using arrive_and_wait(2) or greater
values.
>+ wait();
>+ }
>+
>+ private:
>+ alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
>+ };
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_LATCH
>diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
>new file mode 100644
>index 00000000000..865d6c4aecb
>--- /dev/null
>+++ b/libstdc++-v3/include/std/semaphore
>@@ -0,0 +1,92 @@
>+// <semaphore> -*- C++ -*-
>+
>+// 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/semaphore
>+ * This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE
>+#define _GLIBCXX_SEMAPHORE
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_semaphore 201907L
>+#include <bits/semaphore_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+ template<ptrdiff_t __least_max_value =
>+ __gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
This can use __gnu_cxx::__int_traits too.
>+ class counting_semaphore
>+ {
>+ static_assert(__least_max_value >= 0);
>+
>+ __semaphore_impl<__least_max_value> _M_sem;
>+
>+ public:
>+ explicit counting_semaphore(ptrdiff_t __desired) noexcept
>+ : _M_sem(__desired)
>+ { }
>+
>+ ~counting_semaphore() = default;
>+
>+ counting_semaphore(const counting_semaphore&) = delete;
>+ counting_semaphore& operator=(const counting_semaphore&) = delete;
>+
>+ static constexpr ptrdiff_t
>+ max() noexcept
>+ { return __least_max_value; }
>+
>+ void
>+ release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
>+ { _M_sem._M_release(__update); }
>+
>+ void
>+ acquire() noexcept(noexcept(_M_sem._M_acquire()))
>+ { _M_sem._M_acquire(); }
>+
>+ bool
>+ try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
>+ { return _M_sem._M_try_acquire(); }
>+
>+ template<class _Rep, class _Period>
typename, not class
>+ bool
>+ try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
>+ { return _M_sem._M_try_acquire_for(__rtime); }
>+
>+ template<class _Clock, class _Dur>
typename, not class
>+ bool
>+ try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
>+ { return _M_sem._M_try_acquire_until(__atime); }
>+ };
>+
>+ using binary_semaphore = std::counting_semaphore<1>;
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_SEMAPHORE
>diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
>index d5d42ed0a72..b9c7c6c62a8 100644
>--- a/libstdc++-v3/include/std/version
>+++ b/libstdc++-v3/include/std/version
>@@ -216,12 +216,14 @@
> #ifdef _GLIBCXX_HAS_GTHREADS
> # define __cpp_lib_jthread 201911L
> #endif
>+#define __cpp_lib_latch 201907L
> #define __cpp_lib_list_remove_return_type 201806L
> #define __cpp_lib_math_constants 201907L
> #define __cpp_lib_polymorphic_allocator 201902L
> #if __cpp_lib_concepts
> # define __cpp_lib_ranges 201911L
> #endif
>+#define __cpp_lib_semaphore 201907L
> #define __cpp_lib_shift 201806L
> #define __cpp_lib_span 202002L
> #define __cpp_lib_ssize 201902L
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
>new file mode 100644
>index 00000000000..1ced9d44b20
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
This file should be under testsuite/29_atomics/atomic_ref somewhere,
not under testsuite/29_atomics/atomic
>@@ -0,0 +1,103 @@
>+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <chrono>
>+#include <type_traits>
>+
>+#include <testsuite_hooks.h>
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ Tp aa = val1;
>+ std::atomic_ref<Tp> a(aa);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ a.wait(val1);
>+ if (a.load() != val2)
>+ a = val1;
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(val2);
>+ a.notify_one();
>+ t.join();
>+ return a.load();
>+}
>+
>+template<typename Tp,
>+ bool = std::is_integral_v<Tp>
>+ || std::is_floating_point_v<Tp>>
>+struct check;
>+
>+template<typename Tp>
>+struct check<Tp, true>
>+{
>+ check()
>+ {
>+ Tp a = 0;
>+ Tp b = 42;
>+ VERIFY(check_wait_notify(a, b) == b);
>+ }
>+};
>+
>+template<typename Tp>
>+struct check<Tp, false>
>+{
>+ check(Tp b)
>+ {
>+ Tp a;
>+ VERIFY(check_wait_notify(a, b) == b);
>+ }
>+};
>+
>+struct foo
>+{
>+ long a = 0;
>+ long b = 0;
>+
>+ foo& operator=(foo const&) = default;
>+
>+ friend bool
>+ operator==(foo const& rhs, foo const& lhs)
>+ { return rhs.a == lhs.a && rhs.b == lhs.b; }
>+};
>+
>+int
>+main ()
>+{
>+ check<long>();
>+ check<double>();
>+ check<foo>({42, 48});
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
>new file mode 100644
>index 00000000000..b9fc063c66f
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
>@@ -0,0 +1,59 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <type_traits>
>+#include <chrono>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main ()
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ std::atomic<bool> a(false);
>+ std::atomic<bool> b(false);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ a.wait(false);
>+ if (a.load())
>+ {
>+ b.store(true);
>+ }
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(true);
>+ a.notify_one();
>+ t.join();
>+ VERIFY( b.load() );
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
>new file mode 100644
>index 00000000000..1d032085752
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
And this should be under testsuite/29_atomics/atomic_float
Please take another look at the dir structure under
testsuite/29_atomics/ and locate the new tests with the relevant
types. testsuite/29_atomics/atomic/ is for the generic std::atomic
template.
>@@ -0,0 +1,32 @@
>+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 "generic.h"
>+
>+int
>+main ()
>+{
>+ check<float> f;
>+ check<double> d;
>+ check<long double> l;
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
>new file mode 100644
>index 00000000000..d15b9c86ae6
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
>@@ -0,0 +1,31 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 "generic.h"
>+
>+int
>+main ()
>+{
>+ struct S{ int i; };
>+ check<S> check_s{S{0},S{42}};
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>new file mode 100644
>index 00000000000..a319e8b60a6
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>@@ -0,0 +1,160 @@
>+// 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 <atomic>
>+#include <chrono>
>+#include <condition_variable>
>+#include <concepts>
>+#include <mutex>
>+#include <thread>
>+
>+#include <testsuite_hooks.h>
>+
>+#include <iostream>
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+ requires std::equality_comparable<Tp>
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ std::atomic<Tp> a(val1);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ a.wait(val1);
>+ if (a.load() != val2)
>+ a = val1;
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(val2);
>+ a.notify_one();
>+ t.join();
>+ return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ std::atomic<Tp> a(val1);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ a.wait(val1);
>+ auto v = a.load();
>+ // TODO this needs to zero padding bits when we can do that
>+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
>+ a = val1;
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(val2);
>+ a.notify_one();
>+ t.join();
>+ return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_atomic_wait_notify(Tp val1, Tp val2)
>+ requires std::equality_comparable<Tp>
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ std::atomic<Tp> a(val1);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ std::atomic_wait(&a, val1);
>+ if (a.load() != val2)
>+ a = val1;
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(val2);
>+ std::atomic_notify_one(&a);
>+ t.join();
>+ return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_atomic_wait_notify(Tp val1, Tp val2)
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ std::atomic<Tp> a(val1);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ std::atomic_wait(&a, val1);
>+ auto v = a.load();
>+ // TODO this needs to zero padding bits when we can do that
>+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
>+ a = val1;
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(val2);
>+ std::atomic_notify_one(&a);
>+ t.join();
>+ return a.load();
>+}
>+
>+template<typename Tp>
>+struct check
>+{
>+ check(Tp a = 0, Tp b = 42)
>+ {
>+ if constexpr (std::equality_comparable<Tp>)
>+ {
>+ VERIFY( check_wait_notify(a, b) == b);
>+ VERIFY( check_atomic_wait_notify(a, b) == b);
>+ }
>+ else
>+ {
>+ {
>+ // TODO this needs to zero padding bits when we can do that
>+ auto v = check_wait_notify(a, b);
>+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
>+ }
>+
>+ {
>+ // TODO this needs to zero padding bits when we can do that
>+ auto v = check_atomic_wait_notify(a, b);
>+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
>+ }
>+ }
>+ }
>+};
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>new file mode 100644
>index 00000000000..115cb79a040
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>@@ -0,0 +1,65 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 "generic.h"
>+
>+void
>+test01()
>+{
>+ struct S{ int i; };
>+ std::atomic<S> s;
>+
>+ s.wait(S{42});
>+}
>+
>+int
>+main ()
>+{
>+ // check<bool> bb;
>+ check<char> ch;
>+ check<signed char> sch;
>+ check<unsigned char> uch;
>+ check<short> s;
>+ check<unsigned short> us;
>+ check<int> i;
>+ check<unsigned int> ui;
>+ check<long> l;
>+ check<unsigned long> ul;
>+ check<long long> ll;
>+ check<unsigned long long> ull;
>+
>+ check<wchar_t> wch;
>+ check<char8_t> ch8;
>+ check<char16_t> ch16;
>+ check<char32_t> ch32;
>+
>+ check<int8_t> i8;
>+ check<int16_t> i16;
>+ check<int32_t> i32;
>+ check<int64_t> i64;
>+
>+ check<uint8_t> u8;
>+ check<uint16_t> u16;
>+ check<uint32_t> u32;
>+ check<uint64_t> u64;
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>new file mode 100644
>index 00000000000..8531bb2e788
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>@@ -0,0 +1,59 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <type_traits>
>+#include <chrono>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main ()
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ long aa;
>+ long bb;
>+
>+ std::atomic<long*> a(nullptr);
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ a.wait(nullptr);
>+ if (a.load() == &aa)
>+ a.store(&bb);
>+ });
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.store(&aa);
>+ a.notify_one();
>+ t.join();
>+ VERIFY( a.load() == &bb);
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
>new file mode 100644
>index 00000000000..6de7873ecc2
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
>@@ -0,0 +1,61 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { 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 <atomic>
>+#include <chrono>
>+#include <condition_variable>
>+#include <concepts>
>+#include <mutex>
>+#include <thread>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main()
>+{
>+ using namespace std::literals::chrono_literals;
>+
>+ std::mutex m;
>+ std::condition_variable cv;
>+
>+ std::atomic_flag a;
>+ std::atomic_flag b;
>+ std::thread t([&]
>+ {
>+ cv.notify_one();
>+ a.wait(false);
>+ b.test_and_set();
>+ b.notify_one();
>+ });
>+
>+ std::unique_lock<std::mutex> l(m);
>+ cv.wait(l);
>+ std::this_thread::sleep_for(100ms);
>+ a.test_and_set();
>+ a.notify_one();
>+ b.wait(false);
>+ t.join();
>+
>+ VERIFY( a.test() );
>+ VERIFY( b.test() );
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
>new file mode 100644
>index 00000000000..aa203cdf525
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
>@@ -0,0 +1,27 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <latch>
>+
>+#ifndef __cpp_lib_latch
>+# error "Feature-test macro for latch missing in <latch>"
>+#elif __cpp_lib_latch!= 201907L
>+# error "Feature-test macro for latch has wrong value in <latch>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>new file mode 100644
>index 00000000000..318a859ee21
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>@@ -0,0 +1,27 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <version>
>+
>+#ifndef __cpp_lib_latch
>+# error "Feature-test macro for latch missing in <version>"
>+#elif __cpp_lib_latch != 201907L
>+# error "Feature-test macro for latch has wrong value in <version>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>new file mode 100644
>index 00000000000..cf1a31f996b
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>@@ -0,0 +1,50 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+//
>+#include <latch>
>+#include <atomic>
>+#include <thread>
>+#include <testsuite_hooks.h>
>+
>+int main()
>+{
>+ std::atomic<int> a(0);
>+
>+ std::latch l(3);
>+
>+ VERIFY( !l.try_wait() );
>+
>+ auto fn = [&]
>+ {
>+ ++a;
>+ l.count_down();
>+ };
>+
>+ std::thread t0(fn);
>+ std::thread t1(fn);
>+
>+ l.arrive_and_wait();
>+ t0.join();
>+ t1.join();
>+
>+ VERIFY( l.try_wait() );
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>new file mode 100644
>index 00000000000..1bbca687fc3
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>@@ -0,0 +1,27 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <semaphore>
>+
>+#ifndef __cpp_lib_semaphore
>+# error "Feature-test macro for semaphore missing in <semaphore>"
>+#elif __cpp_lib_semaphore != 201907L
>+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>new file mode 100644
>index 00000000000..98743f5e27c
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>@@ -0,0 +1,27 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <version>
>+
>+#ifndef __cpp_lib_semaphore
>+# error "Feature-test macro for semaphore missing in <version>"
>+#elif __cpp_lib_semaphore != 201907L
>+# error "Feature-test macro for semaphore has wrong value in <version>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>new file mode 100644
>index 00000000000..d74cfad53e9
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>@@ -0,0 +1,30 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+
>+int main()
>+{
>+ std::counting_semaphore<-1> sem(2);
>+ return 0;
>+}
>+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>new file mode 100644
>index 00000000000..25280441d07
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>@@ -0,0 +1,55 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <limits>
>+#include <cstddef>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+ std::counting_semaphore<10> s(3);
>+
>+ s.acquire();
>+ VERIFY( s.try_acquire() );
>+ VERIFY( s.try_acquire() );
>+ VERIFY( !s.try_acquire() );
>+ s.release();
>+ VERIFY( s.try_acquire() );
>+}
>+
>+void test02()
>+{
>+ std::binary_semaphore s(1);
>+
>+ s.acquire();
>+ VERIFY( !s.try_acquire() );
>+ s.release();
>+ VERIFY( s.try_acquire() );
>+}
>+
>+
>+int main()
>+{
>+ test01();
>+ test02();
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>new file mode 100644
>index 00000000000..3f450e74661
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>@@ -0,0 +1,85 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+ using namespace std::chrono_literals;
>+ std::counting_semaphore<10> s(2);
>+ s.acquire();
>+
>+ auto const dur = 250ms;
>+ {
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( s.try_acquire_for(dur) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff < dur );
>+ }
>+
>+ {
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( !s.try_acquire_for(dur) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff >= dur );
>+ }
>+}
>+
>+void test02()
>+{
>+ using namespace std::chrono_literals;
>+ std::binary_semaphore s(1);
>+ std::atomic<int> a(0), b(0);
>+ std::thread t([&] {
>+ a.wait(0);
>+ auto const dur = 250ms;
>+ VERIFY( !s.try_acquire_for(dur) );
>+ b++;
>+ b.notify_one();
>+
>+ a.wait(1);
>+ VERIFY( s.try_acquire_for(dur) );
>+ b++;
>+ b.notify_one();
>+ });
>+ t.detach();
>+
>+ s.acquire();
>+ a++;
>+ a.notify_one();
>+ b.wait(0);
>+ s.release();
>+ a++;
>+ a.notify_one();
>+
>+ b.wait(1);
>+}
>+
>+int main()
>+{
>+ test01();
>+ test02();
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>new file mode 100644
>index 00000000000..13bd7487d56
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>@@ -0,0 +1,153 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+ using namespace std::chrono_literals;
>+ std::__platform_semaphore s(2);
>+ s._M_acquire();
>+
>+ auto const dur = 250ms;
>+ {
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( s._M_try_acquire_for(dur) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff < dur );
>+ }
>+
>+ {
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( !s._M_try_acquire_for(dur) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff >= dur );
>+ }
>+}
>+
>+void test02()
>+{
>+ using namespace std::chrono_literals;
>+ std::__platform_semaphore s(1);
>+ std::atomic<int> a(0), b(0);
>+ std::thread t([&] {
>+ a.wait(0);
>+ auto const dur = 250ms;
>+ VERIFY( !s._M_try_acquire_for(dur) );
>+ b++;
>+ b.notify_one();
>+
>+ a.wait(1);
>+ VERIFY( s._M_try_acquire_for(dur) );
>+ b++;
>+ b.notify_one();
>+ });
>+ t.detach();
>+
>+ s._M_acquire();
>+ a++;
>+ a.notify_one();
>+ b.wait(0);
>+ s._M_release(1);
>+ a++;
>+ a.notify_one();
>+
>+ b.wait(1);
>+}
>+
>+void test03()
>+{
>+ using namespace std::chrono_literals;
>+ std::__platform_semaphore s(2);
>+ s._M_acquire();
>+
>+ auto const dur = 250ms;
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( s._M_try_acquire_until(at) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff < dur );
>+ }
>+
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( !s._M_try_acquire_until(at) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff >= dur );
>+ }
>+}
>+
>+void test04()
>+{
>+ using namespace std::chrono_literals;
>+ std::__platform_semaphore s(1);
>+ std::atomic<int> a(0), b(0);
>+ std::thread t([&] {
>+ a.wait(0);
>+ auto const dur = 250ms;
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ VERIFY( !s._M_try_acquire_until(at) );
>+
>+ b++;
>+ b.notify_one();
>+ }
>+
>+ a.wait(1);
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ VERIFY( s._M_try_acquire_until(at) );
>+ }
>+ b++;
>+ b.notify_one();
>+ });
>+ t.detach();
>+
>+ s._M_acquire();
>+ a++;
>+ a.notify_one();
>+ b.wait(0);
>+ s._M_release(1);
>+ a++;
>+ a.notify_one();
>+
>+ b.wait(1);
>+}
>+#endif
>+
>+int main()
>+{
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+ test01();
>+ test02();
>+ test03();
>+ test04();
>+#endif
>+ return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>new file mode 100644
>index 00000000000..af7ab7bac39
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>@@ -0,0 +1,94 @@
>+// 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/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+ using namespace std::chrono_literals;
>+ std::counting_semaphore<10> s(2);
>+ s.acquire();
>+
>+ auto const dur = 250ms;
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( s.try_acquire_until(at) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff < dur );
>+ }
>+
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ auto const t0 = std::chrono::steady_clock::now();
>+ VERIFY( !s.try_acquire_until(at) );
>+ auto const diff = std::chrono::steady_clock::now() - t0;
>+ VERIFY( diff >= dur );
>+ }
>+}
>+
>+void test02()
>+{
>+ using namespace std::chrono_literals;
>+ std::binary_semaphore s(1);
>+ std::atomic<int> a(0), b(0);
>+ std::thread t([&] {
>+ a.wait(0);
>+ auto const dur = 250ms;
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ VERIFY( !s.try_acquire_until(at) );
>+
>+ b++;
>+ b.notify_one();
>+ }
>+
>+ a.wait(1);
>+ {
>+ auto const at = std::chrono::system_clock::now() + dur;
>+ VERIFY( s.try_acquire_until(at) );
>+ }
>+ b++;
>+ b.notify_one();
>+ });
>+ t.detach();
>+
>+ s.acquire();
>+ a++;
>+ a.notify_one();
>+ b.wait(0);
>+ s.release();
>+ a++;
>+ a.notify_one();
>+
>+ b.wait(1);
>+}
>+
>+int main()
>+{
>+ test01();
>+ test02();
>+}
>--
>2.26.2
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] libstdc++: Add C++2a synchronization support
2020-09-03 0:54 [PATCH] " Thomas Rodgers
@ 2020-09-11 23:58 ` Thomas Rodgers
2020-09-28 13:25 ` Jonathan Wakely
` (2 more replies)
0 siblings, 3 replies; 35+ messages in thread
From: Thomas Rodgers @ 2020-09-11 23:58 UTC (permalink / raw)
To: gcc-patches, libstdc++; +Cc: trodgers
From: Thomas Rodgers <trodgers@redhat.com>
This patch supercedes both the Add C++2a synchronization support patch
being replied to *and* the patch adding wait/notify_* to atomic_flag.
Add support for -
* atomic_flag::wait/notify_one/notify_all
* atomic::wait/notify_one/notify_all
* counting_semaphore
* binary_semaphore
* latch
libstdc++-v3/ChangeLog:
* include/Makefile.am (bits_headers): Add new header.
* include/Makefile.in: Regenerate.
* include/bits/atomic_base.h (__atomic_flag::wait): Define.
(__atomic_flag::notify_one): Likewise.
(__atomic_flag::notify_all): Likewise.
(__atomic_base<_Itp>::wait): Likewise.
(__atomic_base<_Itp>::notify_one): Likewise.
(__atomic_base<_Itp>::notify_all): Likewise.
(__atomic_base<_Ptp*>::wait): Likewise.
(__atomic_base<_Ptp*>::notify_one): Likewise.
(__atomic_base<_Ptp*>::notify_all): Likewise.
(__atomic_impl::wait): Likewise.
(__atomic_impl::notify_one): Likewise.
(__atomic_impl::notify_all): Likewise.
(__atomic_float<_Fp>::wait): Likewise.
(__atomic_float<_Fp>::notify_one): Likewise.
(__atomic_float<_Fp>::notify_all): Likewise.
(__atomic_ref<_Tp>::wait): Likewise.
(__atomic_ref<_Tp>::notify_one): Likewise.
(__atomic_ref<_Tp>::notify_all): Likewise.
(atomic_wait<_Tp>): Likewise.
(atomic_wait_explicit<_Tp>): Likewise.
(atomic_notify_one<_Tp>): Likewise.
(atomic_notify_all<_Tp>): Likewise.
* include/bits/atomic_wait.h: New file.
* include/bits/atomic_timed_wait.h: New file.
* include/bits/semaphore_base.h: New file.
* include/std/atomic (atomic<bool>::wait): Define.
(atomic<bool>::wait_one): Likewise.
(atomic<bool>::wait_all): Likewise.
(atomic<_Tp>::wait): Likewise.
(atomic<_Tp>::wait_one): Likewise.
(atomic<_Tp>::wait_all): Likewise.
(atomic<_Tp*>::wait): Likewise.
(atomic<_Tp*>::wait_one): Likewise.
(atomic<_Tp*>::wait_all): Likewise.
* include/std/latch: New file.
* include/std/semaphore: New file.
* include/std/version: Add __cpp_lib_semaphore and
__cpp_lib_latch defines.
* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
* testsuite/30_thread/semaphore/1.cc: New test.
* testsuite/30_thread/semaphore/2.cc: Likewise.
* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
* testsuite/30_thread/latch/1.cc: New test.
* testsuite/30_thread/latch/2.cc: New test.
* testsuite/30_thread/latch/3.cc: New test.
---
libstdc++-v3/include/Makefile.am | 5 +
libstdc++-v3/include/Makefile.in | 5 +
libstdc++-v3/include/bits/atomic_base.h | 195 +++++++++++-
libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
libstdc++-v3/include/bits/atomic_wait.h | 301 ++++++++++++++++++
libstdc++-v3/include/bits/semaphore_base.h | 283 ++++++++++++++++
libstdc++-v3/include/std/atomic | 73 +++++
libstdc++-v3/include/std/latch | 90 ++++++
libstdc++-v3/include/std/semaphore | 92 ++++++
libstdc++-v3/include/std/version | 2 +
.../atomic/wait_notify/atomic_refs.cc | 103 ++++++
.../29_atomics/atomic/wait_notify/bool.cc | 59 ++++
.../29_atomics/atomic/wait_notify/floats.cc | 32 ++
.../29_atomics/atomic/wait_notify/generic.cc | 31 ++
.../29_atomics/atomic/wait_notify/generic.h | 160 ++++++++++
.../atomic/wait_notify/integrals.cc | 65 ++++
.../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
.../29_atomics/atomic_flag/wait_notify/1.cc | 61 ++++
libstdc++-v3/testsuite/30_threads/latch/1.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/2.cc | 27 ++
libstdc++-v3/testsuite/30_threads/latch/3.cc | 50 +++
.../testsuite/30_threads/semaphore/1.cc | 27 ++
.../testsuite/30_threads/semaphore/2.cc | 27 ++
.../semaphore/least_max_value_neg.cc | 30 ++
.../30_threads/semaphore/try_acquire.cc | 55 ++++
.../30_threads/semaphore/try_acquire_for.cc | 85 +++++
.../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
.../30_threads/semaphore/try_acquire_until.cc | 94 ++++++
28 files changed, 2471 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
create mode 100644 libstdc++-v3/include/std/latch
create mode 100644 libstdc++-v3/include/std/semaphore
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
${std_srcdir}/iostream \
${std_srcdir}/istream \
${std_srcdir}/iterator \
+ ${std_srcdir}/latch \
${std_srcdir}/limits \
${std_srcdir}/list \
${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
${std_srcdir}/ratio \
${std_srcdir}/regex \
${std_srcdir}/scoped_allocator \
+ ${std_srcdir}/semaphore \
${std_srcdir}/set \
${std_srcdir}/shared_mutex \
${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
${bits_srcdir}/allocated_ptr.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/atomic_base.h \
+ ${bits_srcdir}/atomic_wait.h \
+ ${bits_srcdir}/atomic_timed_wait.h \
${bits_srcdir}/atomic_futex.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
${bits_srcdir}/regex_compiler.tcc \
${bits_srcdir}/regex_executor.h \
${bits_srcdir}/regex_executor.tcc \
+ ${bits_srcdir}/semaphore_base.h \
${bits_srcdir}/shared_ptr.h \
${bits_srcdir}/shared_ptr_atomic.h \
${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
#include <bits/atomic_lockfree_defines.h>
#include <bits/move.h>
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
#ifndef _GLIBCXX_ALWAYS_INLINE
#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
-
// Base types for atomics.
template<typename _IntTp>
struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_load(&_M_i, &__v, int(__m));
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
}
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(bool __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]()
+ { return this->test(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
#endif // C++20
_GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__int_type __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __int_type
fetch_add(__int_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__m1), int(__m2));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__pointer_type __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(&_M_p, __old,
+ [__m, this, __old]()
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_p, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_p, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__success), int(__failure));
}
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(const _Tp* __ptr, _Val<_Tp> __old,
+ memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(__ptr, __old,
+ [=]() { return load(__ptr, __m) == __old; });
+ }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, false); }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE _Tp
fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(&_M_fp); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(&_M_fp); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
private:
_Tp* _M_ptr;
};
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
+ // TODO add const volatile overload
+
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ enum class __atomic_wait_status { no_timeout, timeout };
+
+ namespace __detail
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __platform_wait_clock_t = chrono::steady_clock;
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until_impl(__platform_wait_t* __addr,
+ __platform_wait_t __val,
+ const chrono::time_point<__platform_wait_clock_t,
+ _Duration>& __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())
+ };
+
+ auto __e = syscall (SYS_futex, __addr,
+ static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+ __val, &__rt, nullptr,
+ static_cast<int>(__futex_wait_flags::__bitset_match_any));
+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+ std::terminate();
+ return (__platform_wait_clock_t::now() < __atime)
+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+ }
+
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+ if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+ {
+ return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __platform_wait_clock_t::time_point __s_entry =
+ __platform_wait_clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
+ __atomic_wait_status::no_timeout)
+ return __atomic_wait_status::no_timeout;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+ }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<mutex>& __lock,
+ 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())
+ };
+
+ pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+ CLOCK_MONOTONIC,
+ &__ts);
+ return (chrono::steady_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+ }
+#endif
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ 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_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+ &__ts);
+ return (chrono::system_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
+
+ // return true if timeout
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ using __clock_t = chrono::steady_clock;
+#else
+ using __clock_t = chrono::system_clock;
+#endif
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+ return __atomic_wait_status::no_timeout;
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+
+ struct __timed_waiters : __waiters
+ {
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ _M_do_wait_until(__platform_wait_t __version,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+ __platform_wait_t __cur = 0;
+ __waiters::__lock_t __l(_M_mtx);
+ while (__cur <= __version)
+ {
+ if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
+ __atomic_wait_status::timeout)
+ return __atomic_wait_status::timeout;
+
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+ return __atomic_wait_status::no_timeout;
+#endif
+ }
+
+ static __timed_waiters&
+ _S_timed_for(void* __t)
+ {
+ static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+ return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+ }
+ };
+ } // namespace __detail
+
+ template<typename _Tp, typename _Pred,
+ typename _Clock, typename _Duration>
+ bool
+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+ auto __version = __w._M_enter_wait();
+ do
+ {
+ __atomic_wait_status __res;
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+ __old,
+ __atime);
+ }
+ else
+ {
+ __res = __w._M_do_wait_until(__version, __atime);
+ }
+ if (__res == __atomic_wait_status::timeout)
+ return false;
+ }
+ while (!__pred() && __atime < _Clock::now());
+ __w._M_leave_wait();
+
+ // if timed out, return false
+ return (_Clock::now() < __atime);
+ }
+
+ template<typename _Tp, typename _Pred,
+ typename _Rep, typename _Period>
+ bool
+ __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ if (!__rtime.count())
+ return false; // no rtime supplied, and spin did not acquire
+
+ using __dur = chrono::steady_clock::duration;
+ auto __reltime = chrono::duration_cast<__dur>(__rtime);
+ if (__reltime < __rtime)
+ ++__reltime;
+
+
+ return __atomic_wait_until(__addr, __old, std::move(__pred),
+ chrono::steady_clock::now() + __reltime);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..21ec3d38c94
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,301 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __detail
+ {
+ using __platform_wait_t = int;
+
+ constexpr auto __atomic_spin_count_1 = 16;
+ constexpr auto __atomic_spin_count_2 = 12;
+
+ inline constexpr
+ auto __platform_wait_max_value =
+ __gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+ template<typename _Tp>
+ inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ = is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+ = false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ enum class __futex_wait_flags : int
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+ __private_flag = 128,
+#else
+ __private_flag = 0,
+#endif
+ __wait = 0,
+ __wake = 1,
+ __wait_bitset = 9,
+ __wake_bitset = 10,
+ __wait_private = __wait | __private_flag,
+ __wake_private = __wake | __private_flag,
+ __wait_bitset_private = __wait_bitset | __private_flag,
+ __wake_bitset_private = __wake_bitset | __private_flag,
+ __bitset_match_any = -1
+ };
+
+ template<typename _Tp>
+ void
+ __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+ {
+ auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wait_private),
+ __val, nullptr);
+ if (__e && !(errno == EINTR || errno == EAGAIN))
+ std::terminate();
+ }
+
+ template<typename _Tp>
+ void
+ __platform_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ syscall (SYS_futex, static_cast<const void*>(__addr),
+ static_cast<int>(__futex_wait_flags::__wake_private),
+ __all ? INT_MAX : 1);
+ }
+#endif
+
+ struct __waiters
+ {
+ __platform_wait_t alignas(64) _M_ver = 0;
+ __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __lock_t = std::unique_lock<std::mutex>;
+ mutable __lock_t::mutex_type _M_mtx;
+
+# ifdef __GTHREAD_COND_INIT
+ mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+ __waiters() noexcept = default;
+# else
+ mutable __gthread_cond_t _M_cv;
+ __waiters() noexcept
+ {
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+ }
+# endif
+#endif
+
+ __platform_wait_t
+ _M_enter_wait() noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+ __atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ return __res;
+ }
+
+ void
+ _M_leave_wait() noexcept
+ {
+ __atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ }
+
+ void
+ _M_do_wait(__platform_wait_t __version) noexcept
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_wait(&_M_ver, __version);
+#else
+ __platform_wait_t __cur = 0;
+ while (__cur <= __version)
+ {
+ __waiters::__lock_t __l(_M_mtx);
+ auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+ if (__e)
+ std::terminate();
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+#endif
+ }
+
+ __platform_wait_t
+ _M_waiting() const noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
+
+ void
+ _M_notify(bool __all) noexcept
+ {
+ __atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_notify(&_M_ver, __all);
+#else
+ auto __e = __gthread_cond_broadcast(&_M_cv);
+ if (__e)
+ __throw_system_error(__e);
+#endif
+ }
+
+ static __waiters&
+ _S_for(const void* __t)
+ {
+ const unsigned char __mask = 0xf;
+ static __waiters __w[__mask + 1];
+
+ auto __key = _Hash_impl::hash(__t) & __mask;
+ return __w[__key];
+ }
+ };
+
+ struct __waiter
+ {
+ __waiters& _M_w;
+ __platform_wait_t _M_version;
+
+ template<typename _Tp>
+ __waiter(const _Tp* __addr) noexcept
+ : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+ , _M_version(_M_w._M_enter_wait())
+ { }
+
+ ~__waiter()
+ { _M_w._M_leave_wait(); }
+
+ void _M_do_wait() noexcept
+ { _M_w._M_do_wait(_M_version); }
+ };
+
+ void
+ __thread_relax() noexcept
+ {
+#if defined __i386__ || defined __x86_64__
+ __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ void
+ __thread_yield() noexcept
+ {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ } // namespace __detail
+
+ template<typename _Pred>
+ bool
+ __atomic_spin(_Pred __pred) noexcept
+ {
+ for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+ {
+ if (__pred())
+ return true;
+
+ if (__i < __detail::__atomic_spin_count_2)
+ __detail::__thread_relax();
+ else
+ __detail::__thread_yield();
+ }
+ return false;
+ }
+
+ template<typename _Tp, typename _Pred>
+ void
+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+ {
+ using namespace __detail;
+ if (__atomic_spin(__pred))
+ return;
+
+ __waiter __w(__addr);
+ while (!__pred())
+ {
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_wait(__addr, __old);
+ }
+ else
+ {
+ // TODO support timed backoff when this can be moved into the lib
+ __w._M_do_wait();
+ }
+ }
+ }
+
+ template<typename _Tp>
+ void
+ __atomic_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ using namespace __detail;
+ auto& __w = __waiters::_S_for((void*)__addr);
+ if (!__w._M_waiting())
+ return;
+
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+ }
+ else
+ {
+ __w._M_notify(__all);
+ }
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..ed127a7a953
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- header.
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#include <iostream>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ struct __platform_semaphore
+ {
+ using __clock_t = chrono::system_clock;
+ static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+ explicit __platform_semaphore(ptrdiff_t __count) noexcept
+ {
+ sem_init(&_M_semaphore, 0, __count);
+ }
+
+ __platform_semaphore(const __platform_semaphore&) = delete;
+ __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+ ~__platform_semaphore()
+ { sem_destroy(&_M_semaphore); }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ for (;;)
+ {
+ auto __err = sem_wait(&_M_semaphore);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(std::ptrdiff_t __update) noexcept
+ {
+ for(; __update != 0; --__update)
+ {
+ auto __err = sem_post(&_M_semaphore);
+ if (__err)
+ std::terminate();
+ }
+ }
+
+ bool
+ _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
+ {
+
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ struct timespec __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ for (;;)
+ {
+ auto __err = sem_timedwait(&_M_semaphore, &__ts);
+ if (__err && (errno == EINTR))
+ continue;
+ else if (__err && (errno == ETIMEDOUT))
+ return false;
+ else if (__err && (errno == EINVAL))
+ return false; // caller supplied an invalid __atime
+ else if (__err)
+ std::terminate();
+ else
+ break;
+ }
+ return true;
+ }
+
+ template<typename _Clock, typename _Duration>
+ bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ if constexpr (std::is_same<__clock_t, _Clock>::value)
+ {
+ return _M_try_acquire_until_impl(__atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (_M_try_acquire_until_impl(__s_atime))
+ return true;
+
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ return (_Clock::now() < __atime);
+ }
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+ private:
+ sem_t _M_semaphore;
+ };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+ template<typename _Tp>
+ struct __atomic_semaphore
+ {
+ static_assert(std::is_integral_v<_Tp>);
+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+ explicit __atomic_semaphore(_Tp __count) noexcept
+ : _M_a(__count)
+ { }
+
+ __atomic_semaphore(const __atomic_semaphore&) = delete;
+ __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_acquire() noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ __atomic_wait(&_M_a, __old, __pred);
+ }
+
+ bool
+ _M_try_acquire() noexcept
+ {
+ auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ if (__old == 0)
+ return false;
+
+ return __atomic_spin([this, &__old]
+ {
+ return __atomic_impl::compare_exchange_weak(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ });
+ }
+
+ template<typename _Clock, typename _Duration>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ return __atomic_wait_until(&_M_a, __old, __pred, __atime);
+ }
+
+ template<typename _Rep, typename _Period>
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ auto const __pred = [this]
+ {
+ auto __old = __atomic_impl::load(&this->_M_a,
+ memory_order::acquire);
+ if (__old == 0)
+ return false;
+ return __atomic_impl::compare_exchange_strong(&this->_M_a,
+ __old, __old - 1,
+ memory_order::acquire,
+ memory_order::release);
+ };
+
+ auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+ return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ _M_release(ptrdiff_t __update) noexcept
+ {
+ if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
+ return;
+ if (__update > 1)
+ __atomic_impl::notify_all(&_M_a);
+ else
+ __atomic_impl::notify_one(&_M_a);
+ }
+
+ private:
+ alignas(__alignof__(_Tp)) _Tp _M_a;
+ };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+ // Use futex if available and didn't force use of POSIX
+ using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ using __fast_semaphore = __platform_semaphore;
+#else
+ using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+ using __semaphore_impl = conditional_t<
+ (__least_max_value > 1),
+ conditional_t<
+ (__least_max_value <= __fast_semaphore::_S_max),
+ __fast_semaphore,
+ __atomic_semaphore<ptrdiff_t>>,
+ __fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..c15909d9ccb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
compare_exchange_strong(bool& __i1, bool __i2,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+ void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { _M_base.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_base.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_base.notify_all(); }
+#endif
};
#if __cplusplus <= 201703L
@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return compare_exchange_strong(__e, __i, __m,
__cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+ void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]
+ {
+ const auto __v = this->load(__m);
+ // TODO make this ignore padding bits when we can do that
+ return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
+ });
+ }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ void notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+#endif
+
};
#undef _GLIBCXX20_INIT
@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+ { _M_b.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_b.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_b.notify_all(); }
+#endif
__pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order_seq_cst);
}
+
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ inline void
+ atomic_wait(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old) noexcept
+ { __a->wait(__old); }
+
+ template<typename _Tp>
+ inline void
+ atomic_wait_explicit(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old,
+ std::memory_order __m) noexcept
+ { __a->wait(__old, __m); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_one(atomic<_Tp>* __a) noexcept
+ { __a->notify_one(); }
+
+ template<typename _Tp>
+ inline void
+ atomic_notify_all(atomic<_Tp>* __a) noexcept
+ { __a->notify_all(); }
+
+#endif // C++2a
+
// Function templates for atomic_integral and atomic_pointer operations only.
// Some operations (and, or, xor) are only available for atomic integrals,
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..bd06db5aa7f
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,90 @@
+// <latch> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ class latch
+ {
+ public:
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+ constexpr explicit latch(ptrdiff_t __expected) noexcept
+ : _M_a(__expected) { }
+
+ ~latch() = default;
+ latch(const latch&) = delete;
+ latch& operator=(const latch&) = delete;
+
+ _GLIBCXX_ALWAYS_INLINE void
+ count_down(ptrdiff_t __update = 1)
+ {
+ auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
+ if (__old == __update)
+ __atomic_impl::notify_all(&_M_a);
+ }
+
+ _GLIBCXX_ALWAYS_INLINE bool
+ try_wait() const noexcept
+ { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ wait() const
+ {
+ auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+ __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ arrive_and_wait(ptrdiff_t __update = 1)
+ {
+ count_down();
+ wait();
+ }
+
+ private:
+ alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+ };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..865d6c4aecb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<ptrdiff_t __least_max_value =
+ __gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
+ class counting_semaphore
+ {
+ static_assert(__least_max_value >= 0);
+
+ __semaphore_impl<__least_max_value> _M_sem;
+
+ public:
+ explicit counting_semaphore(ptrdiff_t __desired) noexcept
+ : _M_sem(__desired)
+ { }
+
+ ~counting_semaphore() = default;
+
+ counting_semaphore(const counting_semaphore&) = delete;
+ counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __least_max_value; }
+
+ void
+ release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+ { _M_sem._M_release(__update); }
+
+ void
+ acquire() noexcept(noexcept(_M_sem._M_acquire()))
+ { _M_sem._M_acquire(); }
+
+ bool
+ try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+ { return _M_sem._M_try_acquire(); }
+
+ template<class _Rep, class _Period>
+ bool
+ try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+ { return _M_sem._M_try_acquire_for(__rtime); }
+
+ template<class _Clock, class _Dur>
+ bool
+ try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+ { return _M_sem._M_try_acquire_until(__atime); }
+ };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..b9c7c6c62a8 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,12 +216,14 @@
#ifdef _GLIBCXX_HAS_GTHREADS
# define __cpp_lib_jthread 201911L
#endif
+#define __cpp_lib_latch 201907L
#define __cpp_lib_list_remove_return_type 201806L
#define __cpp_lib_math_constants 201907L
#define __cpp_lib_polymorphic_allocator 201902L
#if __cpp_lib_concepts
# define __cpp_lib_ranges 201911L
#endif
+#define __cpp_lib_semaphore 201907L
#define __cpp_lib_shift 201806L
#define __cpp_lib_span 202002L
#define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ Tp aa = val1;
+ std::atomic_ref<Tp> a(aa);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp,
+ bool = std::is_integral_v<Tp>
+ || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+ check()
+ {
+ Tp a = 0;
+ Tp b = 42;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+ check(Tp b)
+ {
+ Tp a;
+ VERIFY(check_wait_notify(a, b) == b);
+ }
+};
+
+struct foo
+{
+ long a = 0;
+ long b = 0;
+
+ foo& operator=(foo const&) = default;
+
+ friend bool
+ operator==(foo const& rhs, foo const& lhs)
+ { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+ check<long>();
+ check<double>();
+ check<foo>({42, 48});
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..b9fc063c66f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<bool> a(false);
+ std::atomic<bool> b(false);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ if (a.load())
+ {
+ b.store(true);
+ }
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(true);
+ a.notify_one();
+ t.join();
+ VERIFY( b.load() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
new file mode 100644
index 00000000000..1d032085752
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+int
+main ()
+{
+ check<float> f;
+ check<double> d;
+ check<long double> l;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..d15b9c86ae6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+int
+main ()
+{
+ struct S{ int i; };
+ check<S> check_s{S{0},S{42}};
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,160 @@
+// 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+ requires std::equality_comparable<Tp>
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ auto v = a.load();
+ // TODO this needs to zero padding bits when we can do that
+ if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+ check(Tp a = 0, Tp b = 42)
+ {
+ if constexpr (std::equality_comparable<Tp>)
+ {
+ VERIFY( check_wait_notify(a, b) == b);
+ VERIFY( check_atomic_wait_notify(a, b) == b);
+ }
+ else
+ {
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+ }
+
+ {
+ // TODO this needs to zero padding bits when we can do that
+ auto v = check_atomic_wait_notify(a, b);
+ VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+ }
+ }
+ }
+};
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
new file mode 100644
index 00000000000..115cb79a040
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 "generic.h"
+
+void
+test01()
+{
+ struct S{ int i; };
+ std::atomic<S> s;
+
+ s.wait(S{42});
+}
+
+int
+main ()
+{
+ // check<bool> bb;
+ check<char> ch;
+ check<signed char> sch;
+ check<unsigned char> uch;
+ check<short> s;
+ check<unsigned short> us;
+ check<int> i;
+ check<unsigned int> ui;
+ check<long> l;
+ check<unsigned long> ul;
+ check<long long> ll;
+ check<unsigned long long> ull;
+
+ check<wchar_t> wch;
+ check<char8_t> ch8;
+ check<char16_t> ch16;
+ check<char32_t> ch32;
+
+ check<int8_t> i8;
+ check<int16_t> i16;
+ check<int32_t> i32;
+ check<int64_t> i64;
+
+ check<uint8_t> u8;
+ check<uint16_t> u16;
+ check<uint32_t> u32;
+ check<uint64_t> u64;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ long aa;
+ long bb;
+
+ std::atomic<long*> a(nullptr);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(nullptr);
+ if (a.load() == &aa)
+ a.store(&bb);
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(&aa);
+ a.notify_one();
+ t.join();
+ VERIFY( a.load() == &bb);
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..6de7873ecc2
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { 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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic_flag a;
+ std::atomic_flag b;
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(false);
+ b.test_and_set();
+ b.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.test_and_set();
+ a.notify_one();
+ b.wait(false);
+ t.join();
+
+ VERIFY( a.test() );
+ VERIFY( b.test() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+ std::atomic<int> a(0);
+
+ std::latch l(3);
+
+ VERIFY( !l.try_wait() );
+
+ auto fn = [&]
+ {
+ ++a;
+ l.count_down();
+ };
+
+ std::thread t0(fn);
+ std::thread t1(fn);
+
+ l.arrive_and_wait();
+ t0.join();
+ t1.join();
+
+ VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+ std::counting_semaphore<-1> sem(2);
+ return 0;
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::counting_semaphore<10> s(3);
+
+ s.acquire();
+ VERIFY( s.try_acquire() );
+ VERIFY( s.try_acquire() );
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+ std::binary_semaphore s(1);
+
+ s.acquire();
+ VERIFY( !s.try_acquire() );
+ s.release();
+ VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s.try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_for(dur) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ VERIFY( !s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+
+ a.wait(1);
+ VERIFY( s._M_try_acquire_for(dur) );
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+void test03()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(2);
+ s._M_acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s._M_try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test04()
+{
+ using namespace std::chrono_literals;
+ std::__platform_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s._M_try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s._M_try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s._M_acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s._M_release(1);
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+ test01();
+ test02();
+ test03();
+ test04();
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// 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/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ using namespace std::chrono_literals;
+ std::counting_semaphore<10> s(2);
+ s.acquire();
+
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff < dur );
+ }
+
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ auto const t0 = std::chrono::steady_clock::now();
+ VERIFY( !s.try_acquire_until(at) );
+ auto const diff = std::chrono::steady_clock::now() - t0;
+ VERIFY( diff >= dur );
+ }
+}
+
+void test02()
+{
+ using namespace std::chrono_literals;
+ std::binary_semaphore s(1);
+ std::atomic<int> a(0), b(0);
+ std::thread t([&] {
+ a.wait(0);
+ auto const dur = 250ms;
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( !s.try_acquire_until(at) );
+
+ b++;
+ b.notify_one();
+ }
+
+ a.wait(1);
+ {
+ auto const at = std::chrono::system_clock::now() + dur;
+ VERIFY( s.try_acquire_until(at) );
+ }
+ b++;
+ b.notify_one();
+ });
+ t.detach();
+
+ s.acquire();
+ a++;
+ a.notify_one();
+ b.wait(0);
+ s.release();
+ a++;
+ a.notify_one();
+
+ b.wait(1);
+}
+
+int main()
+{
+ test01();
+ test02();
+}
--
2.26.2
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2020-11-26 16:26 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-21 23:54 [PATCH] libstdc++: Add C++2a synchronization support David Edelsohn
2020-11-22 1:27 ` Jonathan Wakely
2020-11-22 12:29 ` Iain Sandoe
2020-11-22 13:37 ` Jonathan Wakely
2020-11-23 18:31 ` Jonathan Wakely
2020-11-23 18:31 ` Jonathan Wakely
2020-11-24 1:48 ` David Edelsohn
2020-11-23 18:30 ` Jonathan Wakely
-- strict thread matches above, loose matches on Subject: below --
2020-10-23 10:28 [PATCH] t/trodgers/c2a_synchronization Jonathan Wakely
2020-10-26 21:48 ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
2020-10-27 10:23 ` Jonathan Wakely
2020-11-20 22:44 ` Thomas Rodgers
2020-11-22 21:13 ` Stephan Bergmann
2020-11-23 18:33 ` Jonathan Wakely
2020-11-22 21:41 ` Stephan Bergmann
2020-11-23 18:32 ` Jonathan Wakely
2020-11-21 15:16 ` Andreas Schwab
2020-11-21 17:04 ` Jonathan Wakely
2020-11-21 17:39 ` Jonathan Wakely
2020-11-22 0:36 ` H.J. Lu
2020-11-23 14:50 ` Jonathan Wakely
2020-11-24 23:45 ` Jonathan Wakely
2020-11-25 1:07 ` Jonathan Wakely
2020-11-25 10:35 ` Jonathan Wakely
2020-11-25 12:32 ` Jonathan Wakely
2020-11-25 18:39 ` Jonathan Wakely
2020-11-26 16:26 ` Jonathan Wakely
2020-11-23 16:08 ` Jonathan Wakely
2020-09-03 0:54 [PATCH] " Thomas Rodgers
2020-09-11 23:58 ` [PATCH] libstdc++: " Thomas Rodgers
2020-09-28 13:25 ` Jonathan Wakely
2020-10-01 23:37 ` Thomas Rodgers
2020-10-02 15:40 ` Thomas Rodgers
2020-09-28 13:30 ` Jonathan Wakely
2020-09-28 13:36 ` Jonathan Wakely
2020-09-28 21:29 ` Thomas Rodgers
2020-09-29 9:44 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).