[PATCH] libstdc++: Add C++2a synchronization support
Jonathan Wakely
jwakely@redhat.com
Mon Sep 28 13:25:31 GMT 2020
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
>
>
More information about the Libstdc++
mailing list