libstdc++: Add C++2a synchronization support

Message ID 20200911235832.2673678-1-rodgert@appliantology.com
State Superseded
Headers show
Series
  • libstdc++: Add C++2a synchronization support
Related show

Commit Message

Thomas Rodgers Sept. 11, 2020, 11:58 p.m.
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

-- 
2.26.2

Comments

Hongtao Liu via Gcc-patches Sept. 28, 2020, 1:25 p.m. | #1
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

>

>
Hongtao Liu via Gcc-patches Sept. 28, 2020, 1:30 p.m. | #2
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 \
Hongtao Liu via Gcc-patches Sept. 28, 2020, 1:36 p.m. | #3
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);

>+	  }
Hongtao Liu via Gcc-patches Sept. 28, 2020, 9:29 p.m. | #4
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);

>>+	  }
Hongtao Liu via Gcc-patches Sept. 29, 2020, 9:44 a.m. | #5
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!

Patch

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();
+}