public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Add C++2a synchronization support
@ 2020-05-10  0:01 Thomas Rodgers
  2020-05-11 14:05 ` Jonathan Wakely
  0 siblings, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-05-10  0:01 UTC (permalink / raw)
  To: gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 3028 bytes --]

* Note, this patch supersedes my previous atomic wait and semaphore
patches.

Add support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
        * include/Makefile.in: Regenerate.
        * include/bits/atomic_base.h (__atomic_base<_Itp>:wait): Define.
        (__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.h: New File.
        * testsuite/30_thread/semaphore/1.cc: New test.
        * testsuite/30_thread/semaphore/2.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_futex.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


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: le patch --]
[-- Type: text/x-patch, Size: 82165 bytes --]

From 436ab6fd5286a6467792263fbfbd603ba0f0c04d Mon Sep 17 00:00:00 2001
From: Thomas Rodgers <rodgert@appliantology.com>
Date: Mon, 6 Apr 2020 17:58:47 -0700
Subject: [PATCH] Add C++2a synchronization support

Add support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>:wait): Define.
	(__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.h: New File.
        * testsuite/30_thread/semaphore/1.cc: New test.
        * testsuite/30_thread/semaphore/2.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_futex.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       | 162 +++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 270 +++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 280 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 270 +++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 libstdc++-v3/include/std/latch                |  91 ++++++
 libstdc++-v3/include/std/semaphore            |  81 +++++
 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.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 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 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 ++++++
 .../30_threads/semaphore/try_acquire_futex.cc |  51 ++++
 .../30_threads/semaphore/try_acquire_posix.cc | 169 +++++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 26 files changed, 2235 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.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/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/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_futex.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 80aeb3f8959..b3ac1a3365f 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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/Makefile.in b/libstdc++-v3/include/Makefile.in
index eb437ad8d8d..e73ff8b3e64 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -397,6 +397,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch\
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -414,6 +415,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 \
@@ -445,6 +447,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 \
@@ -519,6 +523,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 87fe0bd6000..b2cec0f1722 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,11 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#include <iostream>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -542,6 +546,30 @@ _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
+      {
+	__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
+      { __atomic_notify(&_M_i, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __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
@@ -803,6 +831,30 @@ _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
+      {
+	__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
+      { __atomic_notify(&_M_p, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __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
@@ -891,6 +943,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
+      {
+	__atomic_wait(__ptr, *std::__addressof(__old),
+		      [=]()
+		      { return load(__ptr, __m) == *std::__addressof(__old); });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      { __atomic_notify(__ptr, false); }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      { __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
@@ -1144,6 +1223,23 @@ _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
@@ -1281,6 +1377,22 @@ _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); }
+
     private:
       _Tp* _M_ptr;
     };
@@ -1376,6 +1488,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1531,6 +1659,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1640,6 +1784,22 @@ _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); }
+
       _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..10f0fe50ed9
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,270 @@
+// -*- 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
+    enum
+    {
+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+      __futex_bitset_match_any = 0xffffffff
+    };
+
+    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, __futex_wait_bitset_private, __val, &__rt,
+			    nullptr, __futex_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 (std::is_same<__platform_wait_clock_t, _Clock>::value)
+	  {
+	    return __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 (__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, std::unique_lock<std::mutex>& __lock,
+			     const chrono::time_point<std::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, std::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, std::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 (__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(int32_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+	  int32_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
+		return __atomic_wait_status::__timeout;
+
+	      int32_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;
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return (__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 (__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>::__value)
+	    {
+	      __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 (__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..32070a54f40
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,280 @@
+// -*- 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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// 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;
+
+    template<class _Tp>
+      struct __platform_wait_uses_type
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
+				      __platform_wait_t>::value };
+#else
+	enum { __value = std::false_type::value };
+#endif
+      };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __futex_private_flag = 128,
+#else
+      __futex_private_flag = 0,
+#endif
+      __futex_wait = 0,
+      __futex_wake = 1,
+      __futex_wait_bitset = 9,
+      __futex_wake_bitset = 10,
+      __futex_wait_private = __futex_wait | __futex_private_flag,
+      __futex_wake_private = __futex_wake | __futex_private_flag
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+    {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && !(errno == EINTR || errno == EAGAIN))
+	 std::terminate();
+    }
+
+    void
+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+    {
+      syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
+    }
+#endif
+
+    struct alignas(64) __waiters
+    {
+      int32_t alignas(64) _M_ver = 0;
+      int32_t alignas(64) _M_wait = 0;
+
+      // TODO make this used only where we don't have futexes
+      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
+
+      int32_t
+      _M_enter_wait() noexcept
+      {
+	int32_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(int32_t __version) const noexcept
+      {
+	int32_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();
+	    int32_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+      }
+
+      int32_t
+      _M_waiting() const noexcept
+	{
+	  int32_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);
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+      }
+
+      static __waiters&
+      _S_for(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;
+      int32_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for((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<class _Pred>
+    bool
+    __atomic_spin(_Pred __pred) noexcept
+    {
+      for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < _GLIBCXX_SPIN_COUNT_2)
+	    __detail::__thread_relax();
+	  else
+	    __detail::__thread_yield();
+	}
+      return false;
+    }
+
+  template<class _Tp, class _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>::__value)
+	    {
+	      __platform_wait((__platform_wait_t*)(void*) __addr, __old);
+	    }
+	  else
+	    {
+	      // TODO support timed backoff when this can be moved into the lib
+	      __w._M_do_wait();
+	    }
+	}
+    }
+
+  template<class _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>::__value)
+	{
+	  __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..b3c83bbc70b
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,270 @@
+// -*- 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.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+#include <limits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_t>
+    struct __platform_semaphore
+    {
+      using __clock_t = chrono::system_clock;
+
+      __platform_semaphore(ptrdiff_t __count) noexcept
+      {
+	static_assert( __least_max_t <= SEM_VALUE_MAX, "__least_max_t > SEM_VALUE_MAX");
+	auto __e = sem_init(&_M_semaphore, 0, __count);
+	if (__e)
+	  std::terminate();
+      }
+
+      ~__platform_semaphore()
+      {
+	auto __e = sem_destroy(&_M_semaphore);
+	if (__e)
+	  std::terminate();
+      }
+
+      _GLIBCXX_ALWAYS_INLINE void
+      acquire() noexcept
+      {
+	auto __err = sem_wait(&_M_semaphore);
+	if (__err)
+	  std::terminate();
+      }
+
+      template<typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE bool
+	__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())
+	  };
+
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err)
+	      std::terminate();
+	  return true;
+	}
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE bool
+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	{
+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
+	    {
+	      return __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 (__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
+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{ return try_acquire_until(__clock_t::now() + __rtime); }
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE void
+	release(ptrdiff_t __update) noexcept
+	{
+	  do
+	    {
+	      auto __err = sem_post(&_M_semaphore);
+	      if (__err)
+		std::terminate();
+	    } while (--__update);
+	}
+
+      private:
+	sem_t _M_semaphore;
+      };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	static constexpr size_t _S_alignment = __alignof__(_Tp);
+
+	__atomic_semaphore(_Tp __count)
+	  : _M_a(__count)
+	{ }
+
+	_GLIBCXX_ALWAYS_INLINE void
+	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
+	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
+	  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
+	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
+      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(_S_alignment) _Tp _M_a;
+    };
+
+#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_t>
+    using __semaphore_base = __platform_semaphore<__least_max_t>;
+#else
+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  template<ptrdiff_t __least_max_t>
+    using __semaphore_base = std::conditional<(__least_max_t > 0
+					      && __least_max_t < std::numeric_limits<__detail::__platform_wait_t>::max()),
+					      __atomic_semaphore<__detail::__platform_wait_t>,
+					      __atomic_semaphore<ptrdiff_t>>::type;
+				            // __platform_semaphore
+#  else
+#    ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_t>
+    using __semaphore_base = std::conditional<(__least_max_t > 0 && __least_max_t <= SEM_VALUE_MAX),
+					      __platform_semaphore<__least_max_t>,
+					      __atomic_semaphore<ptrdiff_t>>::type;
+#    else
+  template<ptrdiff_t __least_max_t>
+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
+#    endif
+#  endif
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index a455286a784..3f18774031d 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
@@ -352,6 +365,19 @@ _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) noexcept
+    { _M_i.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_i.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_i.notify_all(); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -590,6 +616,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
@@ -1342,6 +1380,29 @@ _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..0099877416e
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,91 @@
+//<latch> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ *	This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <limits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class latch
+  {
+    static constexpr size_t _S_alignment = __alignof__(ptrdiff_t);
+  public:
+    static constexpr
+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+    max() noexcept
+    { return numeric_limits<ptrdiff_t>::max(); }
+
+    constexpr explicit latch(ptrdiff_t __expected) : _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(_S_alignment) 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..b51940b46ac
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,81 @@
+//<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>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<ptrdiff_t __least_max_value = std::numeric_limits<ptrdiff_t>::max()>
+    class counting_semaphore
+    {
+      __semaphore_base<__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)
+      { _M_sem.release(__update); }
+
+      void acquire()
+      { _M_sem.acquire(); }
+
+      bool try_acquire() noexcept
+      { return _M_sem.try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+	{ return _M_sem.try_acquire_for(__rel_time); }
+
+      template<class _Clock, class _Duration>
+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+	{ return _M_sem.try_acquire_until(__abs_time); }
+    };
+
+ 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 c3a5bd26e63..390990282b0 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -188,6 +188,8 @@
 #endif
 #define __cpp_lib_type_identity 201806L
 #define __cpp_lib_unwrap_ref 201811L
+#define __cpp_lib_semaphore 201907L
+#define __cpp_lib_latch 201907L
 
 #if _GLIBCXX_HOSTED
 #undef __cpp_lib_array_constexpr
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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..0da374ece87
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,88 @@
+// -*- 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.
+
+// 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 <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;
+
+  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_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);
+		  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>
+struct check
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+    VERIFY(check_atomic_wait_notify(a, b) == b);
+  }
+};
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..2afd19a7d14
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,56 @@
+// { 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 ()
+{
+  // 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/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..756727f33b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..10bb500d261
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019-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..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..d38cef86cfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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..965554a3c28
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019-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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
new file mode 100644
index 00000000000..5e05606e97f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+void test01()
+{
+  // the implementation optimizes for values of least_max_t that can fit
+  // in a futex, make sure we cover the case where least_max_t doesn't
+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
+  std::counting_semaphore<least_max_t> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  test01();
+#endif
+}
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..bf99fd3cf8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  // The implementation supports posix as an implementation strategy
+  // make sure we cover that case
+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+
+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()
+{
+  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 test03()
+{
+  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);
+}
+
+void test04()
+{
+  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 test05()
+{
+  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);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+#endif
+}
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..cc67c5c0bf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-05-10  0:01 [PATCH] Add C++2a synchronization support Thomas Rodgers
@ 2020-05-11 14:05 ` Jonathan Wakely
  2020-05-11 15:43   ` Thomas Rodgers
  2020-05-11 20:59   ` Thomas Rodgers
  0 siblings, 2 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-05-11 14:05 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++

On 09/05/20 17:01 -0700, Thomas Rodgers via Libstdc++ wrote:
>* Note, this patch supersedes my previous atomic wait and semaphore
>patches.
>
>Add support for -
>        atomic wait/notify_one/notify_all
>        counting_semaphore
>        binary_semaphore
>        latch
>
>        * include/Makefile.am (bits_headers): Add new header.
>        * include/Makefile.in: Regenerate.
>        * include/bits/atomic_base.h (__atomic_base<_Itp>:wait): Define.

Should be two colons before wait.

>diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
>index eb437ad8d8d..e73ff8b3e64 100644
>--- a/libstdc++-v3/include/Makefile.in
>+++ b/libstdc++-v3/include/Makefile.in

Generated files don't need to be in the patch.

>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>index 87fe0bd6000..b2cec0f1722 100644
>--- a/libstdc++-v3/include/bits/atomic_base.h
>+++ b/libstdc++-v3/include/bits/atomic_base.h
>@@ -37,6 +37,11 @@
> #include <bits/atomic_lockfree_defines.h>
> #include <bits/move.h>
> 
>+#if __cplusplus > 201703L
>+#include <bits/atomic_wait.h>
>+#include <iostream>

<iostream> shouldn't be here (it adds runtime cost, as well as
compile-time).

>@@ -542,6 +546,30 @@ _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

Please format everything to <= 80 columns (ideally < 80).

>+      wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>+      {
>+	__atomic_wait(&_M_p, __old,

This should be qualified to prevent ADL.

>+		      [__m, this, __old]()
>+		      { return this->load(__m) != __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_notify(&_M_p, false); }

Qualify to prevent ADL here too, and all similar calls.

>+#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
>+      {
>+	__atomic_wait(__ptr, *std::__addressof(__old),

Can't this just be __old instead of *std::__addressof(__old) ?

>+		      [=]()
>+		      { return load(__ptr, __m) == *std::__addressof(__old); });

Same here?

>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..10f0fe50ed9
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>@@ -0,0 +1,270 @@
>+// -*- 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 };

Blank line before and after this enum definition please.

>+  namespace __detail
>+  {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+    enum
>+    {
>+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
>+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
>+      __futex_bitset_match_any = 0xffffffff
>+    };
>+
>+    using __platform_wait_clock_t = chrono::steady_clock;

Blank line after this using-decl please.

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

Eventually we'll want to move the rest of this function (which doesn't
depend on the template argument) into the compiled library, but it's
better to be header-only for now.

>+	struct timespec __rt =
>+	{
>+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	  static_cast<long>(__ns.count())
>+	};
>+
>+	auto __e = syscall (SYS_futex, __addr, __futex_wait_bitset_private, __val, &__rt,
>+			    nullptr, __futex_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 (std::is_same<__platform_wait_clock_t, _Clock>::value)

This is C++20 so you can use is_same_v here, which uses the intrinsic
directly and avoids instantiating the is_same class template.

>+	  {
>+	    return __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 (__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, std::unique_lock<std::mutex>& __lock,
>+			     const chrono::time_point<std::chrono::steady_clock, _Duration>& __atime)

The std:: qualification here isn't needed (and doesn't help with
keeping the line below 80 cols).

>+      {
>+	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, std::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, std::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 (__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(int32_t __version,
>+			 const chrono::time_point<_Clock, _Duration>& __atime)
>+	{
>+	  int32_t __cur = 0;
>+	  __waiters::__lock_t __l(_M_mtx);
>+	  while (__cur <= __version)
>+	    {
>+	      if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
>+		return __atomic_wait_status::__timeout;
>+
>+	      int32_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;
>+	}
>+
>+      static __timed_waiters&
>+      _S_timed_for(void* __t)
>+      {
>+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
>+	return (__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 (__atomic_spin(__pred))

Qualify to prevent ADL.

>+	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>::__value)
>+	    {
>+	      __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 (__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..32070a54f40
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>@@ -0,0 +1,280 @@
>+// -*- 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>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <climits>
>+#include <unistd.h>
>+#include <syscall.h>
>+#endif
>+
>+#define _GLIBCXX_SPIN_COUNT_1 16
>+#define _GLIBCXX_SPIN_COUNT_2 12
>+
>+// 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;
>+
>+    template<class _Tp>

This should be typename not class.

>+      struct __platform_wait_uses_type
>+      {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,

This should be remove_cv_t.

>+				      __platform_wait_t>::value };
>+#else
>+	enum { __value = std::false_type::value };
>+#endif

There's no need to use the C++03 enum hack here, it should just derive
from true_type or false_type.

     template<typename _Tp>
       struct __platform_wait_uses_type
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
       : is_same<std::remove_cv_t<_Tp>, __platform_wait_t>
#else
       : false_type
#endif
       { };

Or better yet, just use a variable template:

     template<typename _Tp>
       inline constexpr bool __platform_wait_uses_type
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
       = is_same_v<std::remove_cv_t<_Tp>, __platform_wait_t>;
#else
       = false;
#endif



>+      };
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+    enum
>+    {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>+      __futex_private_flag = 128,
>+#else
>+      __futex_private_flag = 0,
>+#endif
>+      __futex_wait = 0,
>+      __futex_wake = 1,
>+      __futex_wait_bitset = 9,
>+      __futex_wake_bitset = 10,
>+      __futex_wait_private = __futex_wait | __futex_private_flag,
>+      __futex_wake_private = __futex_wake | __futex_private_flag
>+    };
>+
>+    void
>+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
>+    {
>+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
>+       if (__e && !(errno == EINTR || errno == EAGAIN))
>+	 std::terminate();
>+    }
>+
>+    void
>+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
>+    {
>+      syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
>+    }
>+#endif
>+
>+    struct alignas(64) __waiters

Isn't alignas(64) already implied by the first data member?

>+    {
>+      int32_t alignas(64) _M_ver = 0;
>+      int32_t alignas(64) _M_wait = 0;
>+
>+      // TODO make this used only where we don't have futexes

Don't we always need these even with futexes, for the types that don't
use a 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;

If we moved std::condition_variable into its own header (or
<bits/std_mutex.h>, could we reuse that here instead of using
__gthread_cond_t directly?

>+#else
>+      mutable __gthread_cond_t _M_cv;
>+      __waiters() noexcept
>+      {
>+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
>+      }
>+#endif
>+
>+      int32_t
>+      _M_enter_wait() noexcept
>+      {
>+	int32_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(int32_t __version) const noexcept
>+      {
>+	int32_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();
>+	    int32_t __last = __cur;
>+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
>+	    if (__cur < __last)
>+	      break; // break the loop if version overflows
>+	  }
>+      }
>+
>+      int32_t
>+      _M_waiting() const noexcept
>+	{
>+	  int32_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);
>+	auto __e = __gthread_cond_broadcast(&_M_cv);
>+	if (__e)
>+	  __throw_system_error(__e);
>+      }
>+
>+      static __waiters&
>+      _S_for(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;
>+      int32_t _M_version;
>+
>+      template<typename _Tp>
>+	__waiter(const _Tp* __addr) noexcept
>+	  : _M_w(__waiters::_S_for((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<class _Pred>

s/class/template/

>+    bool
>+    __atomic_spin(_Pred __pred) noexcept
>+    {
>+      for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
>+	{
>+	  if (__pred())
>+	    return true;
>+
>+	  if (__i < _GLIBCXX_SPIN_COUNT_2)
>+	    __detail::__thread_relax();
>+	  else
>+	    __detail::__thread_yield();
>+	}
>+      return false;
>+    }
>+
>+  template<class _Tp, class _Pred>

s/class/template/

>+    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>::__value)
>+	    {
>+	      __platform_wait((__platform_wait_t*)(void*) __addr, __old);
>+	    }
>+	  else
>+	    {
>+	      // TODO support timed backoff when this can be moved into the lib
>+	      __w._M_do_wait();
>+	    }
>+	}
>+    }
>+
>+  template<class _Tp>

s/class/template/

>+    void
>+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>+    {
>+      using namespace __detail;
>+      auto& __w = __waiters::_S_for((void*)__addr);
>+      if (!__w._M_waiting())

When __platform_wait_uses_type<_Tp> is true, will __w._M_waiting()
ever be true? Won't this always return before notifying?

Is there meant to be a __waiter constructed here?

>+	return;
>+
>+      if constexpr (__platform_wait_uses_type<_Tp>::__value)
>+	{
>+	  __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..b3c83bbc70b
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>@@ -0,0 +1,270 @@
>+// -*- 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.h

Should be bits/semaphore_base.h

>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{atomic}

Should be @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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
>+#endif
>+
>+#include <chrono>
>+#include <type_traits>
>+#include <limits>

<ext/numeric_traits.h> is much smaller than <limits> and should be
used for limits of integer types. (I recently added
<bits/int_limits.h> too but that was a mistake that I need to fix).


>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  template<ptrdiff_t __least_max_t>

__least_max_t isn't a type so shouldn't have the _t suffix.

>+    struct __platform_semaphore
>+    {
>+      using __clock_t = chrono::system_clock;
>+
>+      __platform_semaphore(ptrdiff_t __count) noexcept

Should this constructor be explicit?

>+      {
>+	static_assert( __least_max_t <= SEM_VALUE_MAX, "__least_max_t > SEM_VALUE_MAX");

Our static_assert messages should state the positive condition, not
the negative one. So it should be "__least_max_t <= SEM_VALUE_MAX",
which is what the real condition is anyway, so you might as well omit
the string literal.

>+	auto __e = sem_init(&_M_semaphore, 0, __count);
>+	if (__e)
>+	  std::terminate();
>+      }
>+
>+      ~__platform_semaphore()
>+      {
>+	auto __e = sem_destroy(&_M_semaphore);
>+	if (__e)
>+	  std::terminate();
>+      }
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      acquire() noexcept
>+      {
>+	auto __err = sem_wait(&_M_semaphore);
>+	if (__err)
>+	  std::terminate();
>+      }
>+
>+      template<typename _Duration>
>+	_GLIBCXX_ALWAYS_INLINE bool

Do we really need this to be always_inline?

>+	__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())
>+	  };
>+
>+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>+	  if (__err && (errno == ETIMEDOUT))
>+	      return false;
>+	  else if (__err)
>+	      std::terminate();
>+	  return true;
>+	}
>+
>+      template<typename _Clock, typename _Duration>
>+	_GLIBCXX_ALWAYS_INLINE bool

always_inline?

>+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+	{
>+	  if constexpr (std::is_same<__clock_t, _Clock>::value)

is_same_v

>+	    {
>+	      return __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 (__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
>+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+	{ return try_acquire_until(__clock_t::now() + __rtime); }
>+
>+      template<typename _Clock, typename _Duration>
>+	_GLIBCXX_ALWAYS_INLINE void
>+	release(ptrdiff_t __update) noexcept
>+	{
>+	  do
>+	    {
>+	      auto __err = sem_post(&_M_semaphore);
>+	      if (__err)
>+		std::terminate();
>+	    } while (--__update);
>+	}
>+
>+      private:
>+	sem_t _M_semaphore;
>+      };
>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+
>+    template<typename _Tp>
>+      struct __atomic_semaphore
>+      {
>+	static constexpr size_t _S_alignment = __alignof__(_Tp);
>+
>+	__atomic_semaphore(_Tp __count)

Should this be explicit?

>+	  : _M_a(__count)
>+	{ }
>+
>+	_GLIBCXX_ALWAYS_INLINE void
>+	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
>+	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
>+	  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
>+	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
>+      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(_S_alignment) _Tp _M_a;

Could this just use alignas(__alignof__(_Tp)) _Tp here? There's no
need for the _S_alignment constant if it's only used in one place.

>+    };
>+
>+#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
>+  template<ptrdiff_t __least_max_t>

Rename __least_max_t here too.

>+    using __semaphore_base = __platform_semaphore<__least_max_t>;
>+#else
>+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+  template<ptrdiff_t __least_max_t>
>+    using __semaphore_base = std::conditional<(__least_max_t > 0

This should use conditional_t<> not conditional<>::type.

The least-max_value can't be negative. If it's zero, can't we use a
futex or semaphore? So the '__least_max_t > 0' condition is wrong?

>+					      && __least_max_t < std::numeric_limits<__detail::__platform_wait_t>::max()),

Should that be <= rather than < ?

>+					      __atomic_semaphore<__detail::__platform_wait_t>,
>+					      __atomic_semaphore<ptrdiff_t>>::type;
>+				            // __platform_semaphore
>+#  else
>+#    ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE

Please use '#elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE' here to avoid
an extra level of #if nesting.

>+  template<ptrdiff_t __least_max_t>
>+    using __semaphore_base = std::conditional<(__least_max_t > 0 && __least_max_t <= SEM_VALUE_MAX),
>+					      __platform_semaphore<__least_max_t>,
>+					      __atomic_semaphore<ptrdiff_t>>::type;
>+#    else
>+  template<ptrdiff_t __least_max_t>
>+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>+#    endif
>+#  endif
>+#endif
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+
>+#endif
>diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>index a455286a784..3f18774031d 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
>@@ -352,6 +365,19 @@ _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) noexcept
>+    { _M_i.wait(__old, __m); }
>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_i.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_i.notify_all(); }
>+#endif
>+
>     };
> #undef _GLIBCXX20_INIT
> 
>@@ -590,6 +616,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
>@@ -1342,6 +1380,29 @@ _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..0099877416e
>--- /dev/null
>+++ b/libstdc++-v3/include/std/latch
>@@ -0,0 +1,91 @@
>+//<latch> -*- C++ -*-

A space before <latch>.

>+
>+// 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.

Align "This" with "@file" here.

>+ */
>+
>+#ifndef _GLIBCXX_LATCH
>+#define _GLIBCXX_LATCH
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_latch 201907L
>+
>+#include <bits/atomic_base.h>
>+#include <limits>

Use <ext/numeric_traits.h> here too.

>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  class latch
>+  {
>+    static constexpr size_t _S_alignment = __alignof__(ptrdiff_t);
>+  public:
>+    static constexpr
>+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
>+    max() noexcept
>+    { return numeric_limits<ptrdiff_t>::max(); }
>+
>+    constexpr explicit latch(ptrdiff_t __expected) : _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(_S_alignment) ptrdiff_t _M_a;

Just use __alignof__ directly here and get rid of _S_alignment?

>+  };
>+_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..b51940b46ac
>--- /dev/null
>+++ b/libstdc++-v3/include/std/semaphore
>@@ -0,0 +1,81 @@
>+//<semaphore> -*- C++ -*-

A space before <semaphore>.

>+
>+// 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.

Align "This" with "@file" here.

>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE
>+#define _GLIBCXX_SEMAPHORE
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_semaphore 201907L
>+#include <bits/semaphore_base.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  template<ptrdiff_t __least_max_value = std::numeric_limits<ptrdiff_t>::max()>
>+    class counting_semaphore
>+    {

I don't see a static_assert making it ill-formed to use a negative
value for __least_max_value. Is that enforced somewhere else?

The standard says it's ill-formed, so we should also have a _neg.cc
test checking that we reject it.

>+      __semaphore_base<__least_max_value> _M_sem;

Blank line after this please.

>+    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)
>+      { _M_sem.release(__update); }
>+
>+      void acquire()
>+      { _M_sem.acquire(); }
>+
>+      bool try_acquire() noexcept
>+      { return _M_sem.try_acquire(); }
>+
>+      template<class _Rep, class _Period>

s/class/template/

>+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
>+	{ return _M_sem.try_acquire_for(__rel_time); }
>+
>+      template<class _Clock, class _Duration>

s/class/template/

>+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
>+	{ return _M_sem.try_acquire_until(__abs_time); }
>+    };
>+
>+ 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 c3a5bd26e63..390990282b0 100644
>--- a/libstdc++-v3/include/std/version
>+++ b/libstdc++-v3/include/std/version
>@@ -188,6 +188,8 @@
> #endif
> #define __cpp_lib_type_identity 201806L
> #define __cpp_lib_unwrap_ref 201811L
>+#define __cpp_lib_semaphore 201907L
>+#define __cpp_lib_latch 201907L

These features aren't supported in a freestanding implementation, so
should be in the #if _GLIBCXX_HOSTED block (and the macros should be
in alphabetical order).

> 
> #if _GLIBCXX_HOSTED
> #undef __cpp_lib_array_constexpr
>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" }

Use { dg-add-options libatomic } instead of adding -latomic -L...


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-05-11 14:05 ` Jonathan Wakely
@ 2020-05-11 15:43   ` Thomas Rodgers
  2020-05-11 17:05     ` Jonathan Wakely
  2020-05-11 20:59   ` Thomas Rodgers
  1 sibling, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-05-11 15:43 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches, libstdc++


Jonathan Wakely writes:

> On 09/05/20 17:01 -0700, Thomas Rodgers via Libstdc++ wrote:

<snip>

>>+#include <iostream>
>
> <iostream> shouldn't be here (it adds runtime cost, as well as
> compile-time).
>
Oversight, not removed after debugging it.

<snip>

>
> Can't this just be __old instead of *std::__addressof(__old) ?
>
Copypasta from elsewhere in the same class, I believe. I'll change it.

<snip>

>
> Isn't alignas(64) already implied by the first data member?
>

Yes

>>+    {
>>+      int32_t alignas(64) _M_ver = 0;
>>+      int32_t alignas(64) _M_wait = 0;
>>+
>>+      // TODO make this used only where we don't have futexes
>
> Don't we always need these even with futexes, for the types that don't
> use a futex?
>

If we have futexes, we can use the address of _M_ver to wake
_M_do_wait() instead of using a condvar for types that don't use a
futex directly.

>>+      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;
>
> If we moved std::condition_variable into its own header (or
> <bits/std_mutex.h>, could we reuse that here instead of using
> __gthread_cond_t directly?
>
Yes, I started down that route initially, I could revisit it in a future
patch as part of also making it's use only necessary when the platform
doesn't support futex.

>>+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>>+    {
>>+      using namespace __detail;
>>+      auto& __w = __waiters::_S_for((void*)__addr);
>>+      if (!__w._M_waiting())
>
> When __platform_wait_uses_type<_Tp> is true, will __w._M_waiting()
> ever be true? Won't this always return before notifying?
>
> Is there meant to be a __waiter constructed here?
>

__waiter (an RAII type) is constructed in the __atomic_wait(), that
increments the _M_wait count on the way into the wait, and decrements it
on the way out, __atomic_notify checks to see if that count is non-zero
before invoking the platform/semaphore notify because it is cheaper
to do the atomic load than it is to make the syscall() when there are no
waiters.

>>+	return;
>>+
>>+      if constexpr (__platform_wait_uses_type<_Tp>::__value)
>>+	{
>>+	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
>>+	}

<snip>

>>+    struct __platform_semaphore
>>+    {
>>+      using __clock_t = chrono::system_clock;
>>+
>>+      __platform_semaphore(ptrdiff_t __count) noexcept
>
> Should this constructor be explicit?
>

Yes.

>>+      template<typename _Duration>
>>+	_GLIBCXX_ALWAYS_INLINE bool
>
> Do we really need this to be always_inline?
>
Probably not, copypasta from elsewhere in the same file.

>>+	__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);

<snip>

>>+    template<typename _Tp>
>>+      struct __atomic_semaphore
>>+      {
>>+	static constexpr size_t _S_alignment = __alignof__(_Tp);
>>+
>>+	__atomic_semaphore(_Tp __count)
>
> Should this be explicit?
>
Yes.

>>+    private:
>>+      alignas(_S_alignment) _Tp _M_a;
>
> Could this just use alignas(__alignof__(_Tp)) _Tp here? There's no
> need for the _S_alignment constant if it's only used in one place.
>
Yes.

>>+    };
>>+
>>+#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
>>+  template<ptrdiff_t __least_max_t>
>
> Rename __least_max_t here too.
>
>>+    using __semaphore_base = __platform_semaphore<__least_max_t>;
>>+#else
>>+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+  template<ptrdiff_t __least_max_t>
>>+    using __semaphore_base = std::conditional<(__least_max_t > 0
>
> This should use conditional_t<> not conditional<>::type.
>
> The least-max_value can't be negative. If it's zero, can't we use a
> futex or semaphore? So the '__least_max_t > 0' condition is wrong?
>

Yes.

>>+					      && __least_max_t < std::numeric_limits<__detail::__platform_wait_t>::max()),
>
> Should that be <= rather than < ?
>

Likely.

>>+					      __atomic_semaphore<__detail::__platform_wait_t>,
>>+					      __atomic_semaphore<ptrdiff_t>>::type;
>>+				            // __platform_semaphore
>>+#  else

<snip...>


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-05-11 15:43   ` Thomas Rodgers
@ 2020-05-11 17:05     ` Jonathan Wakely
  0 siblings, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-05-11 17:05 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++

On 11/05/20 08:43 -0700, Thomas Rodgers wrote:
>
>Jonathan Wakely writes:
>
>> On 09/05/20 17:01 -0700, Thomas Rodgers via Libstdc++ wrote:
>
><snip>
>
>>>+#include <iostream>
>>
>> <iostream> shouldn't be here (it adds runtime cost, as well as
>> compile-time).
>>
>Oversight, not removed after debugging it.
>
><snip>
>
>>
>> Can't this just be __old instead of *std::__addressof(__old) ?
>>
>Copypasta from elsewhere in the same class, I believe. I'll change it.
>
><snip>
>
>>
>> Isn't alignas(64) already implied by the first data member?
>>
>
>Yes
>
>>>+    {
>>>+      int32_t alignas(64) _M_ver = 0;
>>>+      int32_t alignas(64) _M_wait = 0;
>>>+
>>>+      // TODO make this used only where we don't have futexes
>>
>> Don't we always need these even with futexes, for the types that don't
>> use a futex?
>>
>
>If we have futexes, we can use the address of _M_ver to wake
>_M_do_wait() instead of using a condvar for types that don't use a
>futex directly.
>
>>>+      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;
>>
>> If we moved std::condition_variable into its own header (or
>> <bits/std_mutex.h>, could we reuse that here instead of using
>> __gthread_cond_t directly?
>>
>Yes, I started down that route initially, I could revisit it in a future
>patch as part of also making it's use only necessary when the platform
>doesn't support futex.
>
>>>+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>>>+    {
>>>+      using namespace __detail;
>>>+      auto& __w = __waiters::_S_for((void*)__addr);
>>>+      if (!__w._M_waiting())
>>
>> When __platform_wait_uses_type<_Tp> is true, will __w._M_waiting()
>> ever be true? Won't this always return before notifying?
>>
>> Is there meant to be a __waiter constructed here?
>>
>
>__waiter (an RAII type) is constructed in the __atomic_wait(), that
>increments the _M_wait count on the way into the wait, and decrements it
>on the way out, __atomic_notify checks to see if that count is non-zero
>before invoking the platform/semaphore notify because it is cheaper
>to do the atomic load than it is to make the syscall() when there are no
>waiters.

Doh, yes of course.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-05-11 14:05 ` Jonathan Wakely
  2020-05-11 15:43   ` Thomas Rodgers
@ 2020-05-11 20:59   ` Thomas Rodgers
  2020-05-23 22:52     ` Thomas Rodgers
  1 sibling, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-05-11 20:59 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 61 bytes --]

I *think* I have addressed everything in the attached patch.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: updated patch --]
[-- Type: text/x-patch, Size: 79499 bytes --]

commit 24a989d2bf2158bdbe2511310d0583d0c6226f71
Author: Thomas Rodgers <rodgert@appliantology.com>
Date:   Mon Apr 6 17:58:47 2020 -0700

    Add C++2a synchronization support
    
    Add support for -
            atomic wait/notify_one/notify_all
            counting_semaphore
            binary_semaphore
            latch
    
            * include/Makefile.am (bits_headers): Add new header.
            * include/Makefile.in: Regenerate.
            * include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
            (__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.h: New File.
            * 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_futex.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.

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 80aeb3f8959..b3ac1a3365f 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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 87fe0bd6000..73a8a77271e 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;
@@ -542,6 +545,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
@@ -803,6 +831,30 @@ _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
@@ -891,6 +943,32 @@ _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
@@ -1144,6 +1222,23 @@ _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
@@ -1281,6 +1376,22 @@ _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); }
+
     private:
       _Tp* _M_ptr;
     };
@@ -1376,6 +1487,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1531,6 +1658,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1640,6 +1783,22 @@ _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); }
+
       _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..691eed128a6
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,278 @@
+// -*- 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
+    enum
+    {
+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+      __futex_bitset_match_any = 0xffffffff
+    };
+
+    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, __futex_wait_bitset_private, __val, &__rt,
+			    nullptr, __futex_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 (std::is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __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 (__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 (__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(int32_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+	  int32_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
+		return __atomic_wait_status::__timeout;
+
+	      int32_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;
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return (__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..1deacf02cce
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,282 @@
+// -*- 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
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// 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;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__numeric_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
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __futex_private_flag = 128,
+#else
+      __futex_private_flag = 0,
+#endif
+      __futex_wait = 0,
+      __futex_wake = 1,
+      __futex_wait_bitset = 9,
+      __futex_wake_bitset = 10,
+      __futex_wait_private = __futex_wait | __futex_private_flag,
+      __futex_wake_private = __futex_wake | __futex_private_flag
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+    {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && !(errno == EINTR || errno == EAGAIN))
+	 std::terminate();
+    }
+
+    void
+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+    {
+      syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
+    }
+#endif
+
+    struct __waiters
+    {
+      int32_t alignas(64) _M_ver = 0;
+      int32_t alignas(64) _M_wait = 0;
+
+      // TODO make this used only where we don't have futexes
+      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
+
+      int32_t
+      _M_enter_wait() noexcept
+      {
+	int32_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(int32_t __version) const noexcept
+      {
+	int32_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();
+	    int32_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+      }
+
+      int32_t
+      _M_waiting() const noexcept
+	{
+	  int32_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);
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+      }
+
+      static __waiters&
+      _S_for(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;
+      int32_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for((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 < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < _GLIBCXX_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((__platform_wait_t*)(void*) __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..db5949e5b44
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,272 @@
+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    struct __platform_semaphore
+    {
+      using __clock_t = chrono::system_clock;
+
+      __platform_semaphore(ptrdiff_t __count) noexcept
+      {
+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");
+	auto __e = sem_init(&_M_semaphore, 0, __count);
+	if (__e)
+	  std::terminate();
+      }
+
+      ~__platform_semaphore()
+      {
+	auto __e = sem_destroy(&_M_semaphore);
+	if (__e)
+	  std::terminate();
+      }
+
+      _GLIBCXX_ALWAYS_INLINE void
+      acquire() noexcept
+      {
+	auto __err = sem_wait(&_M_semaphore);
+	if (__err)
+	  std::terminate();
+      }
+
+      template<typename _Duration>
+	bool
+	__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())
+	  };
+
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err)
+	      std::terminate();
+	  return true;
+	}
+
+      template<typename _Clock, typename _Duration>
+	bool
+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	{
+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
+	    {
+	      return __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 (__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
+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{ return try_acquire_until(__clock_t::now() + __rtime); }
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE void
+	release(ptrdiff_t __update) noexcept
+	{
+	  do
+	    {
+	      auto __err = sem_post(&_M_semaphore);
+	      if (__err)
+		std::terminate();
+	    } while (--__update);
+	}
+
+      private:
+	sem_t _M_semaphore;
+      };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	__atomic_semaphore(_Tp __count)
+	  : _M_a(__count)
+	{ }
+
+	_GLIBCXX_ALWAYS_INLINE void
+	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
+	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
+	  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
+	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
+      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_REQUIRE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __platform_semaphore<__least_max_value>;
+#else
+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= __detail::__platform_wait_max_value),
+			      __atomic_semaphore<__detail::__platform_wait_t>,
+			      __atomic_semaphore<ptrdiff_t>>;
+
+// __platform_semaphore
+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= SEM_VALUE_MAX),
+			      __platform_semaphore<__least_max_value>,
+			      __atomic_semaphore<ptrdiff_t>>;
+#  else
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
+#  endif
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index a455286a784..3f18774031d 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
@@ -352,6 +365,19 @@ _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) noexcept
+    { _M_i.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_i.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_i.notify_all(); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -590,6 +616,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
@@ -1342,6 +1380,29 @@ _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..aa5299d9fdd
--- /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
+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) : _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..90cf3244647
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,86 @@
+// <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_base<__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)
+      { _M_sem.release(__update); }
+
+      void acquire()
+      { _M_sem.acquire(); }
+
+      bool try_acquire() noexcept
+      { return _M_sem.try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+	{ return _M_sem.try_acquire_for(__rel_time); }
+
+      template<class _Clock, class _Duration>
+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+	{ return _M_sem.try_acquire_until(__abs_time); }
+    };
+
+ 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 c3a5bd26e63..390990282b0 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -188,6 +188,8 @@
 #endif
 #define __cpp_lib_type_identity 201806L
 #define __cpp_lib_unwrap_ref 201811L
+#define __cpp_lib_semaphore 201907L
+#define __cpp_lib_latch 201907L
 
 #if _GLIBCXX_HOSTED
 #undef __cpp_lib_array_constexpr
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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..0da374ece87
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,88 @@
+// -*- 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.
+
+// 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 <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;
+
+  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_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);
+		  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>
+struct check
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+    VERIFY(check_atomic_wait_notify(a, b) == b);
+  }
+};
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..2afd19a7d14
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,56 @@
+// { 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 ()
+{
+  // 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/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..756727f33b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..10bb500d261
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019-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..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..1ac9d261ca5
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2019-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>
+
+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..d38cef86cfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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..965554a3c28
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019-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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
new file mode 100644
index 00000000000..5e05606e97f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+void test01()
+{
+  // the implementation optimizes for values of least_max_t that can fit
+  // in a futex, make sure we cover the case where least_max_t doesn't
+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
+  std::counting_semaphore<least_max_t> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  test01();
+#endif
+}
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..bf99fd3cf8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  // The implementation supports posix as an implementation strategy
+  // make sure we cover that case
+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+
+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()
+{
+  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 test03()
+{
+  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);
+}
+
+void test04()
+{
+  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 test05()
+{
+  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);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+#endif
+}
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..cc67c5c0bf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-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();
+}

[-- Attachment #3: Type: text/plain, Size: 43750 bytes --]


Jonathan Wakely writes:

> On 09/05/20 17:01 -0700, Thomas Rodgers via Libstdc++ wrote:
>>* Note, this patch supersedes my previous atomic wait and semaphore
>>patches.
>>
>>Add support for -
>>        atomic wait/notify_one/notify_all
>>        counting_semaphore
>>        binary_semaphore
>>        latch
>>
>>        * include/Makefile.am (bits_headers): Add new header.
>>        * include/Makefile.in: Regenerate.
>>        * include/bits/atomic_base.h (__atomic_base<_Itp>:wait): Define.
>
> Should be two colons before wait.
>
>>diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
>>index eb437ad8d8d..e73ff8b3e64 100644
>>--- a/libstdc++-v3/include/Makefile.in
>>+++ b/libstdc++-v3/include/Makefile.in
>
> Generated files don't need to be in the patch.
>
>>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>>index 87fe0bd6000..b2cec0f1722 100644
>>--- a/libstdc++-v3/include/bits/atomic_base.h
>>+++ b/libstdc++-v3/include/bits/atomic_base.h
>>@@ -37,6 +37,11 @@
>> #include <bits/atomic_lockfree_defines.h>
>> #include <bits/move.h>
>>
>>+#if __cplusplus > 201703L
>>+#include <bits/atomic_wait.h>
>>+#include <iostream>
>
> <iostream> shouldn't be here (it adds runtime cost, as well as
> compile-time).
>
>>@@ -542,6 +546,30 @@ _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
>
> Please format everything to <= 80 columns (ideally < 80).
>
>>+      wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>>+      {
>>+	__atomic_wait(&_M_p, __old,
>
> This should be qualified to prevent ADL.
>
>>+		      [__m, this, __old]()
>>+		      { return this->load(__m) != __old; });
>>+      }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { __atomic_notify(&_M_p, false); }
>
> Qualify to prevent ADL here too, and all similar calls.
>
>>+#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
>>+      {
>>+	__atomic_wait(__ptr, *std::__addressof(__old),
>
> Can't this just be __old instead of *std::__addressof(__old) ?
>
>>+		      [=]()
>>+		      { return load(__ptr, __m) == *std::__addressof(__old); });
>
> Same here?
>
>>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..10f0fe50ed9
>>--- /dev/null
>>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>@@ -0,0 +1,270 @@
>>+// -*- 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 };
>
> Blank line before and after this enum definition please.
>
>>+  namespace __detail
>>+  {
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+    enum
>>+    {
>>+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
>>+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
>>+      __futex_bitset_match_any = 0xffffffff
>>+    };
>>+
>>+    using __platform_wait_clock_t = chrono::steady_clock;
>
> Blank line after this using-decl please.
>
>>+    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);
>>+
>
> Eventually we'll want to move the rest of this function (which doesn't
> depend on the template argument) into the compiled library, but it's
> better to be header-only for now.
>
>>+	struct timespec __rt =
>>+	{
>>+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>>+	  static_cast<long>(__ns.count())
>>+	};
>>+
>>+	auto __e = syscall (SYS_futex, __addr, __futex_wait_bitset_private, __val, &__rt,
>>+			    nullptr, __futex_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 (std::is_same<__platform_wait_clock_t, _Clock>::value)
>
> This is C++20 so you can use is_same_v here, which uses the intrinsic
> directly and avoids instantiating the is_same class template.
>
>>+	  {
>>+	    return __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 (__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, std::unique_lock<std::mutex>& __lock,
>>+			     const chrono::time_point<std::chrono::steady_clock, _Duration>& __atime)
>
> The std:: qualification here isn't needed (and doesn't help with
> keeping the line below 80 cols).
>
>>+      {
>>+	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, std::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, std::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 (__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(int32_t __version,
>>+			 const chrono::time_point<_Clock, _Duration>& __atime)
>>+	{
>>+	  int32_t __cur = 0;
>>+	  __waiters::__lock_t __l(_M_mtx);
>>+	  while (__cur <= __version)
>>+	    {
>>+	      if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
>>+		return __atomic_wait_status::__timeout;
>>+
>>+	      int32_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;
>>+	}
>>+
>>+      static __timed_waiters&
>>+      _S_timed_for(void* __t)
>>+      {
>>+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
>>+	return (__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 (__atomic_spin(__pred))
>
> Qualify to prevent ADL.
>
>>+	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>::__value)
>>+	    {
>>+	      __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 (__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..32070a54f40
>>--- /dev/null
>>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>>@@ -0,0 +1,280 @@
>>+// -*- 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>
>>+
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+#include <climits>
>>+#include <unistd.h>
>>+#include <syscall.h>
>>+#endif
>>+
>>+#define _GLIBCXX_SPIN_COUNT_1 16
>>+#define _GLIBCXX_SPIN_COUNT_2 12
>>+
>>+// 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;
>>+
>>+    template<class _Tp>
>
> This should be typename not class.
>
>>+      struct __platform_wait_uses_type
>>+      {
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
>
> This should be remove_cv_t.
>
>>+				      __platform_wait_t>::value };
>>+#else
>>+	enum { __value = std::false_type::value };
>>+#endif
>
> There's no need to use the C++03 enum hack here, it should just derive
> from true_type or false_type.
>
>     template<typename _Tp>
>       struct __platform_wait_uses_type
> #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>       : is_same<std::remove_cv_t<_Tp>, __platform_wait_t>
> #else
>       : false_type
> #endif
>       { };
>
> Or better yet, just use a variable template:
>
>     template<typename _Tp>
>       inline constexpr bool __platform_wait_uses_type
> #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>       = is_same_v<std::remove_cv_t<_Tp>, __platform_wait_t>;
> #else
>       = false;
> #endif
>
>
>
>>+      };
>>+
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+    enum
>>+    {
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>>+      __futex_private_flag = 128,
>>+#else
>>+      __futex_private_flag = 0,
>>+#endif
>>+      __futex_wait = 0,
>>+      __futex_wake = 1,
>>+      __futex_wait_bitset = 9,
>>+      __futex_wake_bitset = 10,
>>+      __futex_wait_private = __futex_wait | __futex_private_flag,
>>+      __futex_wake_private = __futex_wake | __futex_private_flag
>>+    };
>>+
>>+    void
>>+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
>>+    {
>>+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
>>+       if (__e && !(errno == EINTR || errno == EAGAIN))
>>+	 std::terminate();
>>+    }
>>+
>>+    void
>>+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
>>+    {
>>+      syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
>>+    }
>>+#endif
>>+
>>+    struct alignas(64) __waiters
>
> Isn't alignas(64) already implied by the first data member?
>
>>+    {
>>+      int32_t alignas(64) _M_ver = 0;
>>+      int32_t alignas(64) _M_wait = 0;
>>+
>>+      // TODO make this used only where we don't have futexes
>
> Don't we always need these even with futexes, for the types that don't
> use a 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;
>
> If we moved std::condition_variable into its own header (or
> <bits/std_mutex.h>, could we reuse that here instead of using
> __gthread_cond_t directly?
>
>>+#else
>>+      mutable __gthread_cond_t _M_cv;
>>+      __waiters() noexcept
>>+      {
>>+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
>>+      }
>>+#endif
>>+
>>+      int32_t
>>+      _M_enter_wait() noexcept
>>+      {
>>+	int32_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(int32_t __version) const noexcept
>>+      {
>>+	int32_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();
>>+	    int32_t __last = __cur;
>>+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
>>+	    if (__cur < __last)
>>+	      break; // break the loop if version overflows
>>+	  }
>>+      }
>>+
>>+      int32_t
>>+      _M_waiting() const noexcept
>>+	{
>>+	  int32_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);
>>+	auto __e = __gthread_cond_broadcast(&_M_cv);
>>+	if (__e)
>>+	  __throw_system_error(__e);
>>+      }
>>+
>>+      static __waiters&
>>+      _S_for(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;
>>+      int32_t _M_version;
>>+
>>+      template<typename _Tp>
>>+	__waiter(const _Tp* __addr) noexcept
>>+	  : _M_w(__waiters::_S_for((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<class _Pred>
>
> s/class/template/
>
>>+    bool
>>+    __atomic_spin(_Pred __pred) noexcept
>>+    {
>>+      for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
>>+	{
>>+	  if (__pred())
>>+	    return true;
>>+
>>+	  if (__i < _GLIBCXX_SPIN_COUNT_2)
>>+	    __detail::__thread_relax();
>>+	  else
>>+	    __detail::__thread_yield();
>>+	}
>>+      return false;
>>+    }
>>+
>>+  template<class _Tp, class _Pred>
>
> s/class/template/
>
>>+    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>::__value)
>>+	    {
>>+	      __platform_wait((__platform_wait_t*)(void*) __addr, __old);
>>+	    }
>>+	  else
>>+	    {
>>+	      // TODO support timed backoff when this can be moved into the lib
>>+	      __w._M_do_wait();
>>+	    }
>>+	}
>>+    }
>>+
>>+  template<class _Tp>
>
> s/class/template/
>
>>+    void
>>+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>>+    {
>>+      using namespace __detail;
>>+      auto& __w = __waiters::_S_for((void*)__addr);
>>+      if (!__w._M_waiting())
>
> When __platform_wait_uses_type<_Tp> is true, will __w._M_waiting()
> ever be true? Won't this always return before notifying?
>
> Is there meant to be a __waiter constructed here?
>
>>+	return;
>>+
>>+      if constexpr (__platform_wait_uses_type<_Tp>::__value)
>>+	{
>>+	  __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..b3c83bbc70b
>>--- /dev/null
>>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>>@@ -0,0 +1,270 @@
>>+// -*- 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.h
>
> Should be bits/semaphore_base.h
>
>>+ *  This is an internal header file, included by other library headers.
>>+ *  Do not attempt to use it directly. @headername{atomic}
>
> Should be @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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
>>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>>+#include <semaphore.h>
>>+#endif
>>+
>>+#include <chrono>
>>+#include <type_traits>
>>+#include <limits>
>
> <ext/numeric_traits.h> is much smaller than <limits> and should be
> used for limits of integer types. (I recently added
> <bits/int_limits.h> too but that was a mistake that I need to fix).
>
>
>>+namespace std _GLIBCXX_VISIBILITY(default)
>>+{
>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>+
>>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>+  template<ptrdiff_t __least_max_t>
>
> __least_max_t isn't a type so shouldn't have the _t suffix.
>
>>+    struct __platform_semaphore
>>+    {
>>+      using __clock_t = chrono::system_clock;
>>+
>>+      __platform_semaphore(ptrdiff_t __count) noexcept
>
> Should this constructor be explicit?
>
>>+      {
>>+	static_assert( __least_max_t <= SEM_VALUE_MAX, "__least_max_t > SEM_VALUE_MAX");
>
> Our static_assert messages should state the positive condition, not
> the negative one. So it should be "__least_max_t <= SEM_VALUE_MAX",
> which is what the real condition is anyway, so you might as well omit
> the string literal.
>
>>+	auto __e = sem_init(&_M_semaphore, 0, __count);
>>+	if (__e)
>>+	  std::terminate();
>>+      }
>>+
>>+      ~__platform_semaphore()
>>+      {
>>+	auto __e = sem_destroy(&_M_semaphore);
>>+	if (__e)
>>+	  std::terminate();
>>+      }
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      acquire() noexcept
>>+      {
>>+	auto __err = sem_wait(&_M_semaphore);
>>+	if (__err)
>>+	  std::terminate();
>>+      }
>>+
>>+      template<typename _Duration>
>>+	_GLIBCXX_ALWAYS_INLINE bool
>
> Do we really need this to be always_inline?
>
>>+	__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())
>>+	  };
>>+
>>+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>>+	  if (__err && (errno == ETIMEDOUT))
>>+	      return false;
>>+	  else if (__err)
>>+	      std::terminate();
>>+	  return true;
>>+	}
>>+
>>+      template<typename _Clock, typename _Duration>
>>+	_GLIBCXX_ALWAYS_INLINE bool
>
> always_inline?
>
>>+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>>+	{
>>+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
>
> is_same_v
>
>>+	    {
>>+	      return __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 (__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
>>+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>>+	{ return try_acquire_until(__clock_t::now() + __rtime); }
>>+
>>+      template<typename _Clock, typename _Duration>
>>+	_GLIBCXX_ALWAYS_INLINE void
>>+	release(ptrdiff_t __update) noexcept
>>+	{
>>+	  do
>>+	    {
>>+	      auto __err = sem_post(&_M_semaphore);
>>+	      if (__err)
>>+		std::terminate();
>>+	    } while (--__update);
>>+	}
>>+
>>+      private:
>>+	sem_t _M_semaphore;
>>+      };
>>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>+
>>+    template<typename _Tp>
>>+      struct __atomic_semaphore
>>+      {
>>+	static constexpr size_t _S_alignment = __alignof__(_Tp);
>>+
>>+	__atomic_semaphore(_Tp __count)
>
> Should this be explicit?
>
>>+	  : _M_a(__count)
>>+	{ }
>>+
>>+	_GLIBCXX_ALWAYS_INLINE void
>>+	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
>>+	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
>>+	  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
>>+	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
>>+      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(_S_alignment) _Tp _M_a;
>
> Could this just use alignas(__alignof__(_Tp)) _Tp here? There's no
> need for the _S_alignment constant if it's only used in one place.
>
>>+    };
>>+
>>+#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
>>+  template<ptrdiff_t __least_max_t>
>
> Rename __least_max_t here too.
>
>>+    using __semaphore_base = __platform_semaphore<__least_max_t>;
>>+#else
>>+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+  template<ptrdiff_t __least_max_t>
>>+    using __semaphore_base = std::conditional<(__least_max_t > 0
>
> This should use conditional_t<> not conditional<>::type.
>
> The least-max_value can't be negative. If it's zero, can't we use a
> futex or semaphore? So the '__least_max_t > 0' condition is wrong?
>
>>+					      && __least_max_t < std::numeric_limits<__detail::__platform_wait_t>::max()),
>
> Should that be <= rather than < ?
>
>>+					      __atomic_semaphore<__detail::__platform_wait_t>,
>>+					      __atomic_semaphore<ptrdiff_t>>::type;
>>+				            // __platform_semaphore
>>+#  else
>>+#    ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>
> Please use '#elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE' here to avoid
> an extra level of #if nesting.
>
>>+  template<ptrdiff_t __least_max_t>
>>+    using __semaphore_base = std::conditional<(__least_max_t > 0 && __least_max_t <= SEM_VALUE_MAX),
>>+					      __platform_semaphore<__least_max_t>,
>>+					      __atomic_semaphore<ptrdiff_t>>::type;
>>+#    else
>>+  template<ptrdiff_t __least_max_t>
>>+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>>+#    endif
>>+#  endif
>>+#endif
>>+
>>+_GLIBCXX_END_NAMESPACE_VERSION
>>+} // namespace std
>>+
>>+#endif
>>diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>>index a455286a784..3f18774031d 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
>>@@ -352,6 +365,19 @@ _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) noexcept
>>+    { _M_i.wait(__old, __m); }
>>+
>>+    // TODO add const volatile overload
>>+
>>+    void notify_one() const noexcept
>>+    { _M_i.notify_one(); }
>>+
>>+    void notify_all() const noexcept
>>+    { _M_i.notify_all(); }
>>+#endif
>>+
>>     };
>> #undef _GLIBCXX20_INIT
>>
>>@@ -590,6 +616,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
>>@@ -1342,6 +1380,29 @@ _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..0099877416e
>>--- /dev/null
>>+++ b/libstdc++-v3/include/std/latch
>>@@ -0,0 +1,91 @@
>>+//<latch> -*- C++ -*-
>
> A space before <latch>.
>
>>+
>>+// 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.
>
> Align "This" with "@file" here.
>
>>+ */
>>+
>>+#ifndef _GLIBCXX_LATCH
>>+#define _GLIBCXX_LATCH
>>+
>>+#pragma GCC system_header
>>+
>>+#if __cplusplus > 201703L
>>+#define __cpp_lib_latch 201907L
>>+
>>+#include <bits/atomic_base.h>
>>+#include <limits>
>
> Use <ext/numeric_traits.h> here too.
>
>>+namespace std _GLIBCXX_VISIBILITY(default)
>>+{
>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>+
>>+  class latch
>>+  {
>>+    static constexpr size_t _S_alignment = __alignof__(ptrdiff_t);
>>+  public:
>>+    static constexpr
>>+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
>>+    max() noexcept
>>+    { return numeric_limits<ptrdiff_t>::max(); }
>>+
>>+    constexpr explicit latch(ptrdiff_t __expected) : _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(_S_alignment) ptrdiff_t _M_a;
>
> Just use __alignof__ directly here and get rid of _S_alignment?
>
>>+  };
>>+_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..b51940b46ac
>>--- /dev/null
>>+++ b/libstdc++-v3/include/std/semaphore
>>@@ -0,0 +1,81 @@
>>+//<semaphore> -*- C++ -*-
>
> A space before <semaphore>.
>
>>+
>>+// 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.
>
> Align "This" with "@file" here.
>
>>+ */
>>+
>>+#ifndef _GLIBCXX_SEMAPHORE
>>+#define _GLIBCXX_SEMAPHORE
>>+
>>+#pragma GCC system_header
>>+
>>+#if __cplusplus > 201703L
>>+#define __cpp_lib_semaphore 201907L
>>+#include <bits/semaphore_base.h>
>>+
>>+namespace std _GLIBCXX_VISIBILITY(default)
>>+{
>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>+
>>+  template<ptrdiff_t __least_max_value = std::numeric_limits<ptrdiff_t>::max()>
>>+    class counting_semaphore
>>+    {
>
> I don't see a static_assert making it ill-formed to use a negative
> value for __least_max_value. Is that enforced somewhere else?
>
> The standard says it's ill-formed, so we should also have a _neg.cc
> test checking that we reject it.
>
>>+      __semaphore_base<__least_max_value> _M_sem;
>
> Blank line after this please.
>
>>+    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)
>>+      { _M_sem.release(__update); }
>>+
>>+      void acquire()
>>+      { _M_sem.acquire(); }
>>+
>>+      bool try_acquire() noexcept
>>+      { return _M_sem.try_acquire(); }
>>+
>>+      template<class _Rep, class _Period>
>
> s/class/template/
>
>>+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
>>+	{ return _M_sem.try_acquire_for(__rel_time); }
>>+
>>+      template<class _Clock, class _Duration>
>
> s/class/template/
>
>>+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
>>+	{ return _M_sem.try_acquire_until(__abs_time); }
>>+    };
>>+
>>+ 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 c3a5bd26e63..390990282b0 100644
>>--- a/libstdc++-v3/include/std/version
>>+++ b/libstdc++-v3/include/std/version
>>@@ -188,6 +188,8 @@
>> #endif
>> #define __cpp_lib_type_identity 201806L
>> #define __cpp_lib_unwrap_ref 201811L
>>+#define __cpp_lib_semaphore 201907L
>>+#define __cpp_lib_latch 201907L
>
> These features aren't supported in a freestanding implementation, so
> should be in the #if _GLIBCXX_HOSTED block (and the macros should be
> in alphabetical order).
>
>>
>> #if _GLIBCXX_HOSTED
>> #undef __cpp_lib_array_constexpr
>>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" }
>
> Use { dg-add-options libatomic } instead of adding -latomic -L...


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-05-11 20:59   ` Thomas Rodgers
@ 2020-05-23 22:52     ` Thomas Rodgers
  2020-05-24 17:41       ` Thomas Rodgers
  2020-06-06  0:29       ` Thomas Rodgers
  0 siblings, 2 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-05-23 22:52 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Jonathan Wakely, Thomas Rodgers

[-- Attachment #1: Type: text/plain, Size: 16 bytes --]

Updated patch.


[-- Attachment #2: 0001-Add-C-2a-synchronization-support.patch --]
[-- Type: application/octet-stream, Size: 86718 bytes --]

From a3decdc503fbaa0805358946ac5646bfa17840e4 Mon Sep 17 00:00:00 2001
From: Thomas Rodgers <rodgert@appliantology.com>
Date: Mon, 6 Apr 2020 17:58:47 -0700
Subject: [PATCH] Add C++2a synchronization support

Add support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
	(__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.h: New File.
        * 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_futex.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       | 161 +++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 282 +++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 291 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 272 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  86 ++++++
 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.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 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          |  28 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_futex.cc |  51 +++
 .../30_threads/semaphore/try_acquire_posix.cc | 169 ++++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 27 files changed, 2291 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.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/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_futex.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 80aeb3f8959..b3ac1a3365f 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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/Makefile.in b/libstdc++-v3/include/Makefile.in
index eb437ad8d8d..e73ff8b3e64 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -397,6 +397,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch\
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -414,6 +415,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 \
@@ -445,6 +447,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 \
@@ -519,6 +523,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 3b66b040976..68d9e7e3756 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;
@@ -562,6 +565,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
@@ -823,6 +851,30 @@ _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
@@ -911,6 +963,32 @@ _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
@@ -1164,6 +1242,23 @@ _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
@@ -1301,6 +1396,22 @@ _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); }
+
     private:
       _Tp* _M_ptr;
     };
@@ -1396,6 +1507,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1551,6 +1678,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1660,6 +1803,22 @@ _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); }
+
       _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..adef80aca61
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,282 @@
+// -*- 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
+    enum
+    {
+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+      __futex_bitset_match_any = 0xffffffff
+    };
+
+    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, __futex_wait_bitset_private, __val, &__rt,
+			    nullptr, __futex_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 (std::is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __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 (__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 (__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 (__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 (__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..92c1e2526ed
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,291 @@
+// -*- 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
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// 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;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__numeric_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
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __futex_private_flag = 128,
+#else
+      __futex_private_flag = 0,
+#endif
+      __futex_wait = 0,
+      __futex_wake = 1,
+      __futex_wait_bitset = 9,
+      __futex_wake_bitset = 10,
+      __futex_wait_private = __futex_wait | __futex_private_flag,
+      __futex_wake_private = __futex_wake | __futex_private_flag
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+    {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && !(errno == EINTR || errno == EAGAIN))
+	 std::terminate();
+    }
+
+    void
+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+    {
+      syscall (SYS_futex, __addr, __futex_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(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((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 < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < _GLIBCXX_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((__platform_wait_t*)(void*) __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..f0c4235d91c
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,272 @@
+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    struct __platform_semaphore
+    {
+      using __clock_t = chrono::system_clock;
+
+      explicit __platform_semaphore(ptrdiff_t __count) noexcept
+      {
+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");
+	auto __e = sem_init(&_M_semaphore, 0, __count);
+	if (__e)
+	  std::terminate();
+      }
+
+      ~__platform_semaphore()
+      {
+	auto __e = sem_destroy(&_M_semaphore);
+	if (__e)
+	  std::terminate();
+      }
+
+      _GLIBCXX_ALWAYS_INLINE void
+      acquire() noexcept
+      {
+	auto __err = sem_wait(&_M_semaphore);
+	if (__err)
+	  std::terminate();
+      }
+
+      template<typename _Duration>
+	bool
+	__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())
+	  };
+
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err)
+	      std::terminate();
+	  return true;
+	}
+
+      template<typename _Clock, typename _Duration>
+	bool
+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	{
+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
+	    {
+	      return __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 (__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
+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{ return try_acquire_until(__clock_t::now() + __rtime); }
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE void
+	release(ptrdiff_t __update) noexcept
+	{
+	  do
+	    {
+	      auto __err = sem_post(&_M_semaphore);
+	      if (__err)
+		std::terminate();
+	    } while (--__update);
+	}
+
+      private:
+	sem_t _M_semaphore;
+      };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	explicit __atomic_semaphore(_Tp __count)
+	  : _M_a(__count)
+	{ }
+
+	_GLIBCXX_ALWAYS_INLINE void
+	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
+	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
+	  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
+	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
+      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_REQUIRE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __platform_semaphore<__least_max_value>;
+#else
+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= __detail::__platform_wait_max_value),
+			      __atomic_semaphore<__detail::__platform_wait_t>,
+			      __atomic_semaphore<ptrdiff_t>>;
+
+// __platform_semaphore
+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= SEM_VALUE_MAX),
+			      __platform_semaphore<__least_max_value>,
+			      __atomic_semaphore<ptrdiff_t>>;
+#  else
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
+#  endif
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index a455286a784..3f18774031d 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
@@ -352,6 +365,19 @@ _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) noexcept
+    { _M_i.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_i.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_i.notify_all(); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -590,6 +616,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
@@ -1342,6 +1380,29 @@ _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..aa5299d9fdd
--- /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
+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) : _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..90cf3244647
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,86 @@
+// <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_base<__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)
+      { _M_sem.release(__update); }
+
+      void acquire()
+      { _M_sem.acquire(); }
+
+      bool try_acquire() noexcept
+      { return _M_sem.try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+	{ return _M_sem.try_acquire_for(__rel_time); }
+
+      template<class _Clock, class _Duration>
+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+	{ return _M_sem.try_acquire_until(__abs_time); }
+    };
+
+ 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 c6bde2cfbda..f09da3344f7 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -189,6 +189,8 @@
 #endif
 #define __cpp_lib_type_identity 201806L
 #define __cpp_lib_unwrap_ref 201811L
+#define __cpp_lib_semaphore 201907L
+#define __cpp_lib_latch 201907L
 
 #if _GLIBCXX_HOSTED
 #undef __cpp_lib_array_constexpr
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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..0da374ece87
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,88 @@
+// -*- 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.
+
+// 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 <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;
+
+  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_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);
+		  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>
+struct check
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+    VERIFY(check_atomic_wait_notify(a, b) == b);
+  }
+};
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..2afd19a7d14
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,56 @@
+// { 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 ()
+{
+  // 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/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..756727f33b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..10bb500d261
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019-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..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..1ac9d261ca5
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2019-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>
+
+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..d38cef86cfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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..965554a3c28
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019-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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
new file mode 100644
index 00000000000..5e05606e97f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+void test01()
+{
+  // the implementation optimizes for values of least_max_t that can fit
+  // in a futex, make sure we cover the case where least_max_t doesn't
+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
+  std::counting_semaphore<least_max_t> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  test01();
+#endif
+}
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..bf99fd3cf8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  // The implementation supports posix as an implementation strategy
+  // make sure we cover that case
+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+
+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()
+{
+  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 test03()
+{
+  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);
+}
+
+void test04()
+{
+  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 test05()
+{
+  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);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+#endif
+}
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..cc67c5c0bf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-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


[-- Attachment #3: Type: text/plain, Size: 47984 bytes --]



> On May 11, 2020, at 1:59 PM, Thomas Rodgers via Libstdc++ <libstdc++@gcc.gnu.org> wrote:
> 
> I *think* I have addressed everything in the attached patch.
> <0001-Add-C-2a-synchronization-support.patch>
> Jonathan Wakely writes:
> 
>> On 09/05/20 17:01 -0700, Thomas Rodgers via Libstdc++ wrote:
>>> * Note, this patch supersedes my previous atomic wait and semaphore
>>> patches.
>>> 
>>> Add support for -
>>>       atomic wait/notify_one/notify_all
>>>       counting_semaphore
>>>       binary_semaphore
>>>       latch
>>> 
>>>       * include/Makefile.am (bits_headers): Add new header.
>>>       * include/Makefile.in: Regenerate.
>>>       * include/bits/atomic_base.h (__atomic_base<_Itp>:wait): Define.
>> 
>> Should be two colons before wait.
>> 
>>> diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
>>> index eb437ad8d8d..e73ff8b3e64 100644
>>> --- a/libstdc++-v3/include/Makefile.in
>>> +++ b/libstdc++-v3/include/Makefile.in
>> 
>> Generated files don't need to be in the patch.
>> 
>>> diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>>> index 87fe0bd6000..b2cec0f1722 100644
>>> --- a/libstdc++-v3/include/bits/atomic_base.h
>>> +++ b/libstdc++-v3/include/bits/atomic_base.h
>>> @@ -37,6 +37,11 @@
>>> #include <bits/atomic_lockfree_defines.h>
>>> #include <bits/move.h>
>>> 
>>> +#if __cplusplus > 201703L
>>> +#include <bits/atomic_wait.h>
>>> +#include <iostream>
>> 
>> <iostream> shouldn't be here (it adds runtime cost, as well as
>> compile-time).
>> 
>>> @@ -542,6 +546,30 @@ _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
>> 
>> Please format everything to <= 80 columns (ideally < 80).
>> 
>>> +      wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>>> +      {
>>> +	__atomic_wait(&_M_p, __old,
>> 
>> This should be qualified to prevent ADL.
>> 
>>> +		      [__m, this, __old]()
>>> +		      { return this->load(__m) != __old; });
>>> +      }
>>> +
>>> +      // TODO add const volatile overload
>>> +
>>> +      _GLIBCXX_ALWAYS_INLINE void
>>> +      notify_one() const noexcept
>>> +      { __atomic_notify(&_M_p, false); }
>> 
>> Qualify to prevent ADL here too, and all similar calls.
>> 
>>> +#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
>>> +      {
>>> +	__atomic_wait(__ptr, *std::__addressof(__old),
>> 
>> Can't this just be __old instead of *std::__addressof(__old) ?
>> 
>>> +		      [=]()
>>> +		      { return load(__ptr, __m) == *std::__addressof(__old); });
>> 
>> Same here?
>> 
>>> 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..10f0fe50ed9
>>> --- /dev/null
>>> +++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>> @@ -0,0 +1,270 @@
>>> +// -*- 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 };
>> 
>> Blank line before and after this enum definition please.
>> 
>>> +  namespace __detail
>>> +  {
>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>> +    enum
>>> +    {
>>> +      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
>>> +      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
>>> +      __futex_bitset_match_any = 0xffffffff
>>> +    };
>>> +
>>> +    using __platform_wait_clock_t = chrono::steady_clock;
>> 
>> Blank line after this using-decl please.
>> 
>>> +    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);
>>> +
>> 
>> Eventually we'll want to move the rest of this function (which doesn't
>> depend on the template argument) into the compiled library, but it's
>> better to be header-only for now.
>> 
>>> +	struct timespec __rt =
>>> +	{
>>> +	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>>> +	  static_cast<long>(__ns.count())
>>> +	};
>>> +
>>> +	auto __e = syscall (SYS_futex, __addr, __futex_wait_bitset_private, __val, &__rt,
>>> +			    nullptr, __futex_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 (std::is_same<__platform_wait_clock_t, _Clock>::value)
>> 
>> This is C++20 so you can use is_same_v here, which uses the intrinsic
>> directly and avoids instantiating the is_same class template.
>> 
>>> +	  {
>>> +	    return __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 (__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, std::unique_lock<std::mutex>& __lock,
>>> +			     const chrono::time_point<std::chrono::steady_clock, _Duration>& __atime)
>> 
>> The std:: qualification here isn't needed (and doesn't help with
>> keeping the line below 80 cols).
>> 
>>> +      {
>>> +	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, std::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, std::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 (__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(int32_t __version,
>>> +			 const chrono::time_point<_Clock, _Duration>& __atime)
>>> +	{
>>> +	  int32_t __cur = 0;
>>> +	  __waiters::__lock_t __l(_M_mtx);
>>> +	  while (__cur <= __version)
>>> +	    {
>>> +	      if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
>>> +		return __atomic_wait_status::__timeout;
>>> +
>>> +	      int32_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;
>>> +	}
>>> +
>>> +      static __timed_waiters&
>>> +      _S_timed_for(void* __t)
>>> +      {
>>> +	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
>>> +	return (__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 (__atomic_spin(__pred))
>> 
>> Qualify to prevent ADL.
>> 
>>> +	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>::__value)
>>> +	    {
>>> +	      __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 (__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..32070a54f40
>>> --- /dev/null
>>> +++ b/libstdc++-v3/include/bits/atomic_wait.h
>>> @@ -0,0 +1,280 @@
>>> +// -*- 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>
>>> +
>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>> +#include <climits>
>>> +#include <unistd.h>
>>> +#include <syscall.h>
>>> +#endif
>>> +
>>> +#define _GLIBCXX_SPIN_COUNT_1 16
>>> +#define _GLIBCXX_SPIN_COUNT_2 12
>>> +
>>> +// 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;
>>> +
>>> +    template<class _Tp>
>> 
>> This should be typename not class.
>> 
>>> +      struct __platform_wait_uses_type
>>> +      {
>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>> +	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
>> 
>> This should be remove_cv_t.
>> 
>>> +				      __platform_wait_t>::value };
>>> +#else
>>> +	enum { __value = std::false_type::value };
>>> +#endif
>> 
>> There's no need to use the C++03 enum hack here, it should just derive
>> from true_type or false_type.
>> 
>>    template<typename _Tp>
>>      struct __platform_wait_uses_type
>> #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>      : is_same<std::remove_cv_t<_Tp>, __platform_wait_t>
>> #else
>>      : false_type
>> #endif
>>      { };
>> 
>> Or better yet, just use a variable template:
>> 
>>    template<typename _Tp>
>>      inline constexpr bool __platform_wait_uses_type
>> #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>      = is_same_v<std::remove_cv_t<_Tp>, __platform_wait_t>;
>> #else
>>      = false;
>> #endif
>> 
>> 
>> 
>>> +      };
>>> +
>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>> +    enum
>>> +    {
>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>>> +      __futex_private_flag = 128,
>>> +#else
>>> +      __futex_private_flag = 0,
>>> +#endif
>>> +      __futex_wait = 0,
>>> +      __futex_wake = 1,
>>> +      __futex_wait_bitset = 9,
>>> +      __futex_wake_bitset = 10,
>>> +      __futex_wait_private = __futex_wait | __futex_private_flag,
>>> +      __futex_wake_private = __futex_wake | __futex_private_flag
>>> +    };
>>> +
>>> +    void
>>> +    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
>>> +    {
>>> +       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
>>> +       if (__e && !(errno == EINTR || errno == EAGAIN))
>>> +	 std::terminate();
>>> +    }
>>> +
>>> +    void
>>> +    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
>>> +    {
>>> +      syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
>>> +    }
>>> +#endif
>>> +
>>> +    struct alignas(64) __waiters
>> 
>> Isn't alignas(64) already implied by the first data member?
>> 
>>> +    {
>>> +      int32_t alignas(64) _M_ver = 0;
>>> +      int32_t alignas(64) _M_wait = 0;
>>> +
>>> +      // TODO make this used only where we don't have futexes
>> 
>> Don't we always need these even with futexes, for the types that don't
>> use a 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;
>> 
>> If we moved std::condition_variable into its own header (or
>> <bits/std_mutex.h>, could we reuse that here instead of using
>> __gthread_cond_t directly?
>> 
>>> +#else
>>> +      mutable __gthread_cond_t _M_cv;
>>> +      __waiters() noexcept
>>> +      {
>>> +	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
>>> +      }
>>> +#endif
>>> +
>>> +      int32_t
>>> +      _M_enter_wait() noexcept
>>> +      {
>>> +	int32_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(int32_t __version) const noexcept
>>> +      {
>>> +	int32_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();
>>> +	    int32_t __last = __cur;
>>> +	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
>>> +	    if (__cur < __last)
>>> +	      break; // break the loop if version overflows
>>> +	  }
>>> +      }
>>> +
>>> +      int32_t
>>> +      _M_waiting() const noexcept
>>> +	{
>>> +	  int32_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);
>>> +	auto __e = __gthread_cond_broadcast(&_M_cv);
>>> +	if (__e)
>>> +	  __throw_system_error(__e);
>>> +      }
>>> +
>>> +      static __waiters&
>>> +      _S_for(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;
>>> +      int32_t _M_version;
>>> +
>>> +      template<typename _Tp>
>>> +	__waiter(const _Tp* __addr) noexcept
>>> +	  : _M_w(__waiters::_S_for((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<class _Pred>
>> 
>> s/class/template/
>> 
>>> +    bool
>>> +    __atomic_spin(_Pred __pred) noexcept
>>> +    {
>>> +      for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
>>> +	{
>>> +	  if (__pred())
>>> +	    return true;
>>> +
>>> +	  if (__i < _GLIBCXX_SPIN_COUNT_2)
>>> +	    __detail::__thread_relax();
>>> +	  else
>>> +	    __detail::__thread_yield();
>>> +	}
>>> +      return false;
>>> +    }
>>> +
>>> +  template<class _Tp, class _Pred>
>> 
>> s/class/template/
>> 
>>> +    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>::__value)
>>> +	    {
>>> +	      __platform_wait((__platform_wait_t*)(void*) __addr, __old);
>>> +	    }
>>> +	  else
>>> +	    {
>>> +	      // TODO support timed backoff when this can be moved into the lib
>>> +	      __w._M_do_wait();
>>> +	    }
>>> +	}
>>> +    }
>>> +
>>> +  template<class _Tp>
>> 
>> s/class/template/
>> 
>>> +    void
>>> +    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>>> +    {
>>> +      using namespace __detail;
>>> +      auto& __w = __waiters::_S_for((void*)__addr);
>>> +      if (!__w._M_waiting())
>> 
>> When __platform_wait_uses_type<_Tp> is true, will __w._M_waiting()
>> ever be true? Won't this always return before notifying?
>> 
>> Is there meant to be a __waiter constructed here?
>> 
>>> +	return;
>>> +
>>> +      if constexpr (__platform_wait_uses_type<_Tp>::__value)
>>> +	{
>>> +	  __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..b3c83bbc70b
>>> --- /dev/null
>>> +++ b/libstdc++-v3/include/bits/semaphore_base.h
>>> @@ -0,0 +1,270 @@
>>> +// -*- 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.h
>> 
>> Should be bits/semaphore_base.h
>> 
>>> + *  This is an internal header file, included by other library headers.
>>> + *  Do not attempt to use it directly. @headername{atomic}
>> 
>> Should be @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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
>>> +#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>>> +#include <semaphore.h>
>>> +#endif
>>> +
>>> +#include <chrono>
>>> +#include <type_traits>
>>> +#include <limits>
>> 
>> <ext/numeric_traits.h> is much smaller than <limits> and should be
>> used for limits of integer types. (I recently added
>> <bits/int_limits.h> too but that was a mistake that I need to fix).
>> 
>> 
>>> +namespace std _GLIBCXX_VISIBILITY(default)
>>> +{
>>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>> +
>>> +#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>> +  template<ptrdiff_t __least_max_t>
>> 
>> __least_max_t isn't a type so shouldn't have the _t suffix.
>> 
>>> +    struct __platform_semaphore
>>> +    {
>>> +      using __clock_t = chrono::system_clock;
>>> +
>>> +      __platform_semaphore(ptrdiff_t __count) noexcept
>> 
>> Should this constructor be explicit?
>> 
>>> +      {
>>> +	static_assert( __least_max_t <= SEM_VALUE_MAX, "__least_max_t > SEM_VALUE_MAX");
>> 
>> Our static_assert messages should state the positive condition, not
>> the negative one. So it should be "__least_max_t <= SEM_VALUE_MAX",
>> which is what the real condition is anyway, so you might as well omit
>> the string literal.
>> 
>>> +	auto __e = sem_init(&_M_semaphore, 0, __count);
>>> +	if (__e)
>>> +	  std::terminate();
>>> +      }
>>> +
>>> +      ~__platform_semaphore()
>>> +      {
>>> +	auto __e = sem_destroy(&_M_semaphore);
>>> +	if (__e)
>>> +	  std::terminate();
>>> +      }
>>> +
>>> +      _GLIBCXX_ALWAYS_INLINE void
>>> +      acquire() noexcept
>>> +      {
>>> +	auto __err = sem_wait(&_M_semaphore);
>>> +	if (__err)
>>> +	  std::terminate();
>>> +      }
>>> +
>>> +      template<typename _Duration>
>>> +	_GLIBCXX_ALWAYS_INLINE bool
>> 
>> Do we really need this to be always_inline?
>> 
>>> +	__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())
>>> +	  };
>>> +
>>> +	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>>> +	  if (__err && (errno == ETIMEDOUT))
>>> +	      return false;
>>> +	  else if (__err)
>>> +	      std::terminate();
>>> +	  return true;
>>> +	}
>>> +
>>> +      template<typename _Clock, typename _Duration>
>>> +	_GLIBCXX_ALWAYS_INLINE bool
>> 
>> always_inline?
>> 
>>> +	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>>> +	{
>>> +	  if constexpr (std::is_same<__clock_t, _Clock>::value)
>> 
>> is_same_v
>> 
>>> +	    {
>>> +	      return __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 (__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
>>> +	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>>> +	{ return try_acquire_until(__clock_t::now() + __rtime); }
>>> +
>>> +      template<typename _Clock, typename _Duration>
>>> +	_GLIBCXX_ALWAYS_INLINE void
>>> +	release(ptrdiff_t __update) noexcept
>>> +	{
>>> +	  do
>>> +	    {
>>> +	      auto __err = sem_post(&_M_semaphore);
>>> +	      if (__err)
>>> +		std::terminate();
>>> +	    } while (--__update);
>>> +	}
>>> +
>>> +      private:
>>> +	sem_t _M_semaphore;
>>> +      };
>>> +#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>> +
>>> +    template<typename _Tp>
>>> +      struct __atomic_semaphore
>>> +      {
>>> +	static constexpr size_t _S_alignment = __alignof__(_Tp);
>>> +
>>> +	__atomic_semaphore(_Tp __count)
>> 
>> Should this be explicit?
>> 
>>> +	  : _M_a(__count)
>>> +	{ }
>>> +
>>> +	_GLIBCXX_ALWAYS_INLINE void
>>> +	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
>>> +	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
>>> +	  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
>>> +	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
>>> +      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(_S_alignment) _Tp _M_a;
>> 
>> Could this just use alignas(__alignof__(_Tp)) _Tp here? There's no
>> need for the _S_alignment constant if it's only used in one place.
>> 
>>> +    };
>>> +
>>> +#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
>>> +  template<ptrdiff_t __least_max_t>
>> 
>> Rename __least_max_t here too.
>> 
>>> +    using __semaphore_base = __platform_semaphore<__least_max_t>;
>>> +#else
>>> +#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>> +  template<ptrdiff_t __least_max_t>
>>> +    using __semaphore_base = std::conditional<(__least_max_t > 0
>> 
>> This should use conditional_t<> not conditional<>::type.
>> 
>> The least-max_value can't be negative. If it's zero, can't we use a
>> futex or semaphore? So the '__least_max_t > 0' condition is wrong?
>> 
>>> +					      && __least_max_t < std::numeric_limits<__detail::__platform_wait_t>::max()),
>> 
>> Should that be <= rather than < ?
>> 
>>> +					      __atomic_semaphore<__detail::__platform_wait_t>,
>>> +					      __atomic_semaphore<ptrdiff_t>>::type;
>>> +				            // __platform_semaphore
>>> +#  else
>>> +#    ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>> 
>> Please use '#elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE' here to avoid
>> an extra level of #if nesting.
>> 
>>> +  template<ptrdiff_t __least_max_t>
>>> +    using __semaphore_base = std::conditional<(__least_max_t > 0 && __least_max_t <= SEM_VALUE_MAX),
>>> +					      __platform_semaphore<__least_max_t>,
>>> +					      __atomic_semaphore<ptrdiff_t>>::type;
>>> +#    else
>>> +  template<ptrdiff_t __least_max_t>
>>> +    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>>> +#    endif
>>> +#  endif
>>> +#endif
>>> +
>>> +_GLIBCXX_END_NAMESPACE_VERSION
>>> +} // namespace std
>>> +
>>> +#endif
>>> diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>>> index a455286a784..3f18774031d 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
>>> @@ -352,6 +365,19 @@ _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) noexcept
>>> +    { _M_i.wait(__old, __m); }
>>> +
>>> +    // TODO add const volatile overload
>>> +
>>> +    void notify_one() const noexcept
>>> +    { _M_i.notify_one(); }
>>> +
>>> +    void notify_all() const noexcept
>>> +    { _M_i.notify_all(); }
>>> +#endif
>>> +
>>>    };
>>> #undef _GLIBCXX20_INIT
>>> 
>>> @@ -590,6 +616,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
>>> @@ -1342,6 +1380,29 @@ _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..0099877416e
>>> --- /dev/null
>>> +++ b/libstdc++-v3/include/std/latch
>>> @@ -0,0 +1,91 @@
>>> +//<latch> -*- C++ -*-
>> 
>> A space before <latch>.
>> 
>>> +
>>> +// 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.
>> 
>> Align "This" with "@file" here.
>> 
>>> + */
>>> +
>>> +#ifndef _GLIBCXX_LATCH
>>> +#define _GLIBCXX_LATCH
>>> +
>>> +#pragma GCC system_header
>>> +
>>> +#if __cplusplus > 201703L
>>> +#define __cpp_lib_latch 201907L
>>> +
>>> +#include <bits/atomic_base.h>
>>> +#include <limits>
>> 
>> Use <ext/numeric_traits.h> here too.
>> 
>>> +namespace std _GLIBCXX_VISIBILITY(default)
>>> +{
>>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>> +
>>> +  class latch
>>> +  {
>>> +    static constexpr size_t _S_alignment = __alignof__(ptrdiff_t);
>>> +  public:
>>> +    static constexpr
>>> +    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
>>> +    max() noexcept
>>> +    { return numeric_limits<ptrdiff_t>::max(); }
>>> +
>>> +    constexpr explicit latch(ptrdiff_t __expected) : _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(_S_alignment) ptrdiff_t _M_a;
>> 
>> Just use __alignof__ directly here and get rid of _S_alignment?
>> 
>>> +  };
>>> +_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..b51940b46ac
>>> --- /dev/null
>>> +++ b/libstdc++-v3/include/std/semaphore
>>> @@ -0,0 +1,81 @@
>>> +//<semaphore> -*- C++ -*-
>> 
>> A space before <semaphore>.
>> 
>>> +
>>> +// 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.
>> 
>> Align "This" with "@file" here.
>> 
>>> + */
>>> +
>>> +#ifndef _GLIBCXX_SEMAPHORE
>>> +#define _GLIBCXX_SEMAPHORE
>>> +
>>> +#pragma GCC system_header
>>> +
>>> +#if __cplusplus > 201703L
>>> +#define __cpp_lib_semaphore 201907L
>>> +#include <bits/semaphore_base.h>
>>> +
>>> +namespace std _GLIBCXX_VISIBILITY(default)
>>> +{
>>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>> +
>>> +  template<ptrdiff_t __least_max_value = std::numeric_limits<ptrdiff_t>::max()>
>>> +    class counting_semaphore
>>> +    {
>> 
>> I don't see a static_assert making it ill-formed to use a negative
>> value for __least_max_value. Is that enforced somewhere else?
>> 
>> The standard says it's ill-formed, so we should also have a _neg.cc
>> test checking that we reject it.
>> 
>>> +      __semaphore_base<__least_max_value> _M_sem;
>> 
>> Blank line after this please.
>> 
>>> +    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)
>>> +      { _M_sem.release(__update); }
>>> +
>>> +      void acquire()
>>> +      { _M_sem.acquire(); }
>>> +
>>> +      bool try_acquire() noexcept
>>> +      { return _M_sem.try_acquire(); }
>>> +
>>> +      template<class _Rep, class _Period>
>> 
>> s/class/template/
>> 
>>> +	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
>>> +	{ return _M_sem.try_acquire_for(__rel_time); }
>>> +
>>> +      template<class _Clock, class _Duration>
>> 
>> s/class/template/
>> 
>>> +	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
>>> +	{ return _M_sem.try_acquire_until(__abs_time); }
>>> +    };
>>> +
>>> + 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 c3a5bd26e63..390990282b0 100644
>>> --- a/libstdc++-v3/include/std/version
>>> +++ b/libstdc++-v3/include/std/version
>>> @@ -188,6 +188,8 @@
>>> #endif
>>> #define __cpp_lib_type_identity 201806L
>>> #define __cpp_lib_unwrap_ref 201811L
>>> +#define __cpp_lib_semaphore 201907L
>>> +#define __cpp_lib_latch 201907L
>> 
>> These features aren't supported in a freestanding implementation, so
>> should be in the #if _GLIBCXX_HOSTED block (and the macros should be
>> in alphabetical order).
>> 
>>> 
>>> #if _GLIBCXX_HOSTED
>>> #undef __cpp_lib_array_constexpr
>>> 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" }
>> 
>> Use { dg-add-options libatomic } instead of adding -latomic -L...
> 


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-05-23 22:52     ` Thomas Rodgers
@ 2020-05-24 17:41       ` Thomas Rodgers
  2020-06-06  0:29       ` Thomas Rodgers
  1 sibling, 0 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-05-24 17:41 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Thomas Rodgers, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 100 bytes --]

The previous patch had a Makefile.in included, should be a property filtered patch attached now.


[-- Attachment #2: 0001-Add-C-2a-synchronization-support_f.patch --]
[-- Type: application/octet-stream, Size: 85450 bytes --]

From a3decdc503fbaa0805358946ac5646bfa17840e4 Mon Sep 17 00:00:00 2001
From: Thomas Rodgers <rodgert@appliantology.com>
Date: Mon, 6 Apr 2020 17:58:47 -0700
Subject: [PATCH] Add C++2a synchronization support

Add support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
	(__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.h: New File.
        * 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_futex.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       | 161 +++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 282 +++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 291 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 272 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  86 ++++++
 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.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 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          |  28 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_futex.cc |  51 +++
 .../30_threads/semaphore/try_acquire_posix.cc | 169 ++++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 27 files changed, 2291 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.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/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_futex.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 80aeb3f8959..b3ac1a3365f 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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 3b66b040976..68d9e7e3756 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;
@@ -562,6 +565,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
@@ -823,6 +851,30 @@ _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
@@ -911,6 +963,32 @@ _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
@@ -1164,6 +1242,23 @@ _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
@@ -1301,6 +1396,22 @@ _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); }
+
     private:
       _Tp* _M_ptr;
     };
@@ -1396,6 +1507,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1551,6 +1678,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1660,6 +1803,22 @@ _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); }
+
       _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..adef80aca61
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,282 @@
+// -*- 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
+    enum
+    {
+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+      __futex_bitset_match_any = 0xffffffff
+    };
+
+    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, __futex_wait_bitset_private, __val, &__rt,
+			    nullptr, __futex_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 (std::is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __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 (__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 (__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 (__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 (__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..92c1e2526ed
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,291 @@
+// -*- 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
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// 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;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__numeric_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
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __futex_private_flag = 128,
+#else
+      __futex_private_flag = 0,
+#endif
+      __futex_wait = 0,
+      __futex_wake = 1,
+      __futex_wait_bitset = 9,
+      __futex_wake_bitset = 10,
+      __futex_wait_private = __futex_wait | __futex_private_flag,
+      __futex_wake_private = __futex_wake | __futex_private_flag
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+    {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && !(errno == EINTR || errno == EAGAIN))
+	 std::terminate();
+    }
+
+    void
+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+    {
+      syscall (SYS_futex, __addr, __futex_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(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((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 < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < _GLIBCXX_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((__platform_wait_t*)(void*) __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..f0c4235d91c
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,272 @@
+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    struct __platform_semaphore
+    {
+      using __clock_t = chrono::system_clock;
+
+      explicit __platform_semaphore(ptrdiff_t __count) noexcept
+      {
+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");
+	auto __e = sem_init(&_M_semaphore, 0, __count);
+	if (__e)
+	  std::terminate();
+      }
+
+      ~__platform_semaphore()
+      {
+	auto __e = sem_destroy(&_M_semaphore);
+	if (__e)
+	  std::terminate();
+      }
+
+      _GLIBCXX_ALWAYS_INLINE void
+      acquire() noexcept
+      {
+	auto __err = sem_wait(&_M_semaphore);
+	if (__err)
+	  std::terminate();
+      }
+
+      template<typename _Duration>
+	bool
+	__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())
+	  };
+
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err)
+	      std::terminate();
+	  return true;
+	}
+
+      template<typename _Clock, typename _Duration>
+	bool
+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	{
+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
+	    {
+	      return __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 (__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
+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{ return try_acquire_until(__clock_t::now() + __rtime); }
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE void
+	release(ptrdiff_t __update) noexcept
+	{
+	  do
+	    {
+	      auto __err = sem_post(&_M_semaphore);
+	      if (__err)
+		std::terminate();
+	    } while (--__update);
+	}
+
+      private:
+	sem_t _M_semaphore;
+      };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	explicit __atomic_semaphore(_Tp __count)
+	  : _M_a(__count)
+	{ }
+
+	_GLIBCXX_ALWAYS_INLINE void
+	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
+	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
+	  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
+	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
+      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_REQUIRE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __platform_semaphore<__least_max_value>;
+#else
+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= __detail::__platform_wait_max_value),
+			      __atomic_semaphore<__detail::__platform_wait_t>,
+			      __atomic_semaphore<ptrdiff_t>>;
+
+// __platform_semaphore
+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= SEM_VALUE_MAX),
+			      __platform_semaphore<__least_max_value>,
+			      __atomic_semaphore<ptrdiff_t>>;
+#  else
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
+#  endif
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index a455286a784..3f18774031d 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
@@ -352,6 +365,19 @@ _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) noexcept
+    { _M_i.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_i.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_i.notify_all(); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -590,6 +616,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
@@ -1342,6 +1380,29 @@ _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..aa5299d9fdd
--- /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
+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) : _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..90cf3244647
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,86 @@
+// <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_base<__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)
+      { _M_sem.release(__update); }
+
+      void acquire()
+      { _M_sem.acquire(); }
+
+      bool try_acquire() noexcept
+      { return _M_sem.try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+	{ return _M_sem.try_acquire_for(__rel_time); }
+
+      template<class _Clock, class _Duration>
+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+	{ return _M_sem.try_acquire_until(__abs_time); }
+    };
+
+ 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 c6bde2cfbda..f09da3344f7 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -189,6 +189,8 @@
 #endif
 #define __cpp_lib_type_identity 201806L
 #define __cpp_lib_unwrap_ref 201811L
+#define __cpp_lib_semaphore 201907L
+#define __cpp_lib_latch 201907L
 
 #if _GLIBCXX_HOSTED
 #undef __cpp_lib_array_constexpr
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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..0da374ece87
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,88 @@
+// -*- 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.
+
+// 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 <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;
+
+  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_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);
+		  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>
+struct check
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+    VERIFY(check_atomic_wait_notify(a, b) == b);
+  }
+};
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..2afd19a7d14
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,56 @@
+// { 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 ()
+{
+  // 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/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..756727f33b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..10bb500d261
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019-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..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..1ac9d261ca5
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2019-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>
+
+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..d38cef86cfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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..965554a3c28
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019-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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
new file mode 100644
index 00000000000..5e05606e97f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+void test01()
+{
+  // the implementation optimizes for values of least_max_t that can fit
+  // in a futex, make sure we cover the case where least_max_t doesn't
+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
+  std::counting_semaphore<least_max_t> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  test01();
+#endif
+}
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..bf99fd3cf8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  // The implementation supports posix as an implementation strategy
+  // make sure we cover that case
+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+
+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()
+{
+  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 test03()
+{
+  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);
+}
+
+void test04()
+{
+  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 test05()
+{
+  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);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+#endif
+}
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..cc67c5c0bf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-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


[-- Attachment #3: Type: text/plain, Size: 49514 bytes --]


> On May 23, 2020, at 3:52 PM, Thomas Rodgers <rodgert@appliantology.com> wrote:
> 
> Updated patch.
> 
> <0001-Add-C-2a-synchronization-support.patch>
> 
>> On May 11, 2020, at 1:59 PM, Thomas Rodgers via Libstdc++ <libstdc++@gcc.gnu.org> wrote:
>> 
>> I *think* I have addressed everything in the attached patch.
>> <0001-Add-C-2a-synchronization-support.patch>
>> Jonathan Wakely writes:
>> 
>>> On 09/05/20 17:01 -0700, Thomas Rodgers via Libstdc++ wrote:
>>>> * Note, this patch supersedes my previous atomic wait and semaphore
>>>> patches.
>>>> 
>>>> Add support for -
>>>>      atomic wait/notify_one/notify_all
>>>>      counting_semaphore
>>>>      binary_semaphore
>>>>      latch
>>>> 
>>>>      * include/Makefile.am (bits_headers): Add new header.
>>>>      * include/Makefile.in: Regenerate.
>>>>      * include/bits/atomic_base.h (__atomic_base<_Itp>:wait): Define.
>>> 
>>> Should be two colons before wait.
>>> 
>>>> diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
>>>> index eb437ad8d8d..e73ff8b3e64 100644
>>>> --- a/libstdc++-v3/include/Makefile.in
>>>> +++ b/libstdc++-v3/include/Makefile.in
>>> 
>>> Generated files don't need to be in the patch.
>>> 
>>>> diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>>>> index 87fe0bd6000..b2cec0f1722 100644
>>>> --- a/libstdc++-v3/include/bits/atomic_base.h
>>>> +++ b/libstdc++-v3/include/bits/atomic_base.h
>>>> @@ -37,6 +37,11 @@
>>>> #include <bits/atomic_lockfree_defines.h>
>>>> #include <bits/move.h>
>>>> 
>>>> +#if __cplusplus > 201703L
>>>> +#include <bits/atomic_wait.h>
>>>> +#include <iostream>
>>> 
>>> <iostream> shouldn't be here (it adds runtime cost, as well as
>>> compile-time).
>>> 
>>>> @@ -542,6 +546,30 @@ _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
>>> 
>>> Please format everything to <= 80 columns (ideally < 80).
>>> 
>>>> +      wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>>>> +      {
>>>> +	__atomic_wait(&_M_p, __old,
>>> 
>>> This should be qualified to prevent ADL.
>>> 
>>>> +		      [__m, this, __old]()
>>>> +		      { return this->load(__m) != __old; });
>>>> +      }
>>>> +
>>>> +      // TODO add const volatile overload
>>>> +
>>>> +      _GLIBCXX_ALWAYS_INLINE void
>>>> +      notify_one() const noexcept
>>>> +      { __atomic_notify(&_M_p, false); }
>>> 
>>> Qualify to prevent ADL here too, and all similar calls.
>>> 
>>>> +#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
>>>> +      {
>>>> +	__atomic_wait(__ptr, *std::__addressof(__old),
>>> 
>>> Can't this just be __old instead of *std::__addressof(__old) ?
>>> 
>>>> +		      [=]()
>>>> +		      { return load(__ptr, __m) == *std::__addressof(__old); });
>>> 
>>> Same here?
>>> 
>>>> 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..10f0fe50ed9
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>>> @@ -0,0 +1,270 @@
>>>> +// -*- 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 };
>>> 
>>> Blank line before and after this enum definition please.
>>> 
>>>> +  namespace __detail
>>>> +  {
>>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>> +    enum
>>>> +    {
>>>> +      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
>>>> +      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
>>>> +      __futex_bitset_match_any = 0xffffffff
>>>> +    };
>>>> +
>>>> +    using __platform_wait_clock_t = chrono::steady_clock;
>>> 
>>> Blank line after this using-decl please.
>>> 
>>>> +    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);
>>>> +
>>> 
>>> Eventually we'll want to move the rest of this function (which doesn't
>>> depend on the template argument) into the compiled library, but it's
>>> better to be header-only for now.
>>> 
>>>> +	struct timespec __rt =
>>>> +	{
>>>> +	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>>>> +	  static_cast<long>(__ns.count())
>>>> +	};
>>>> +
>>>> +	auto __e = syscall (SYS_futex, __addr, __futex_wait_bitset_private, __val, &__rt,
>>>> +			    nullptr, __futex_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 (std::is_same<__platform_wait_clock_t, _Clock>::value)
>>> 
>>> This is C++20 so you can use is_same_v here, which uses the intrinsic
>>> directly and avoids instantiating the is_same class template.
>>> 
>>>> +	  {
>>>> +	    return __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 (__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, std::unique_lock<std::mutex>& __lock,
>>>> +			     const chrono::time_point<std::chrono::steady_clock, _Duration>& __atime)
>>> 
>>> The std:: qualification here isn't needed (and doesn't help with
>>> keeping the line below 80 cols).
>>> 
>>>> +      {
>>>> +	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, std::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, std::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 (__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(int32_t __version,
>>>> +			 const chrono::time_point<_Clock, _Duration>& __atime)
>>>> +	{
>>>> +	  int32_t __cur = 0;
>>>> +	  __waiters::__lock_t __l(_M_mtx);
>>>> +	  while (__cur <= __version)
>>>> +	    {
>>>> +	      if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
>>>> +		return __atomic_wait_status::__timeout;
>>>> +
>>>> +	      int32_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;
>>>> +	}
>>>> +
>>>> +      static __timed_waiters&
>>>> +      _S_timed_for(void* __t)
>>>> +      {
>>>> +	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
>>>> +	return (__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 (__atomic_spin(__pred))
>>> 
>>> Qualify to prevent ADL.
>>> 
>>>> +	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>::__value)
>>>> +	    {
>>>> +	      __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 (__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..32070a54f40
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/include/bits/atomic_wait.h
>>>> @@ -0,0 +1,280 @@
>>>> +// -*- 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>
>>>> +
>>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>> +#include <climits>
>>>> +#include <unistd.h>
>>>> +#include <syscall.h>
>>>> +#endif
>>>> +
>>>> +#define _GLIBCXX_SPIN_COUNT_1 16
>>>> +#define _GLIBCXX_SPIN_COUNT_2 12
>>>> +
>>>> +// 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;
>>>> +
>>>> +    template<class _Tp>
>>> 
>>> This should be typename not class.
>>> 
>>>> +      struct __platform_wait_uses_type
>>>> +      {
>>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>> +	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
>>> 
>>> This should be remove_cv_t.
>>> 
>>>> +				      __platform_wait_t>::value };
>>>> +#else
>>>> +	enum { __value = std::false_type::value };
>>>> +#endif
>>> 
>>> There's no need to use the C++03 enum hack here, it should just derive
>>> from true_type or false_type.
>>> 
>>>   template<typename _Tp>
>>>     struct __platform_wait_uses_type
>>> #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>     : is_same<std::remove_cv_t<_Tp>, __platform_wait_t>
>>> #else
>>>     : false_type
>>> #endif
>>>     { };
>>> 
>>> Or better yet, just use a variable template:
>>> 
>>>   template<typename _Tp>
>>>     inline constexpr bool __platform_wait_uses_type
>>> #ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>     = is_same_v<std::remove_cv_t<_Tp>, __platform_wait_t>;
>>> #else
>>>     = false;
>>> #endif
>>> 
>>> 
>>> 
>>>> +      };
>>>> +
>>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>> +    enum
>>>> +    {
>>>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>>>> +      __futex_private_flag = 128,
>>>> +#else
>>>> +      __futex_private_flag = 0,
>>>> +#endif
>>>> +      __futex_wait = 0,
>>>> +      __futex_wake = 1,
>>>> +      __futex_wait_bitset = 9,
>>>> +      __futex_wake_bitset = 10,
>>>> +      __futex_wait_private = __futex_wait | __futex_private_flag,
>>>> +      __futex_wake_private = __futex_wake | __futex_private_flag
>>>> +    };
>>>> +
>>>> +    void
>>>> +    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
>>>> +    {
>>>> +       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
>>>> +       if (__e && !(errno == EINTR || errno == EAGAIN))
>>>> +	 std::terminate();
>>>> +    }
>>>> +
>>>> +    void
>>>> +    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
>>>> +    {
>>>> +      syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
>>>> +    }
>>>> +#endif
>>>> +
>>>> +    struct alignas(64) __waiters
>>> 
>>> Isn't alignas(64) already implied by the first data member?
>>> 
>>>> +    {
>>>> +      int32_t alignas(64) _M_ver = 0;
>>>> +      int32_t alignas(64) _M_wait = 0;
>>>> +
>>>> +      // TODO make this used only where we don't have futexes
>>> 
>>> Don't we always need these even with futexes, for the types that don't
>>> use a 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;
>>> 
>>> If we moved std::condition_variable into its own header (or
>>> <bits/std_mutex.h>, could we reuse that here instead of using
>>> __gthread_cond_t directly?
>>> 
>>>> +#else
>>>> +      mutable __gthread_cond_t _M_cv;
>>>> +      __waiters() noexcept
>>>> +      {
>>>> +	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
>>>> +      }
>>>> +#endif
>>>> +
>>>> +      int32_t
>>>> +      _M_enter_wait() noexcept
>>>> +      {
>>>> +	int32_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(int32_t __version) const noexcept
>>>> +      {
>>>> +	int32_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();
>>>> +	    int32_t __last = __cur;
>>>> +	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
>>>> +	    if (__cur < __last)
>>>> +	      break; // break the loop if version overflows
>>>> +	  }
>>>> +      }
>>>> +
>>>> +      int32_t
>>>> +      _M_waiting() const noexcept
>>>> +	{
>>>> +	  int32_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);
>>>> +	auto __e = __gthread_cond_broadcast(&_M_cv);
>>>> +	if (__e)
>>>> +	  __throw_system_error(__e);
>>>> +      }
>>>> +
>>>> +      static __waiters&
>>>> +      _S_for(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;
>>>> +      int32_t _M_version;
>>>> +
>>>> +      template<typename _Tp>
>>>> +	__waiter(const _Tp* __addr) noexcept
>>>> +	  : _M_w(__waiters::_S_for((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<class _Pred>
>>> 
>>> s/class/template/
>>> 
>>>> +    bool
>>>> +    __atomic_spin(_Pred __pred) noexcept
>>>> +    {
>>>> +      for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
>>>> +	{
>>>> +	  if (__pred())
>>>> +	    return true;
>>>> +
>>>> +	  if (__i < _GLIBCXX_SPIN_COUNT_2)
>>>> +	    __detail::__thread_relax();
>>>> +	  else
>>>> +	    __detail::__thread_yield();
>>>> +	}
>>>> +      return false;
>>>> +    }
>>>> +
>>>> +  template<class _Tp, class _Pred>
>>> 
>>> s/class/template/
>>> 
>>>> +    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>::__value)
>>>> +	    {
>>>> +	      __platform_wait((__platform_wait_t*)(void*) __addr, __old);
>>>> +	    }
>>>> +	  else
>>>> +	    {
>>>> +	      // TODO support timed backoff when this can be moved into the lib
>>>> +	      __w._M_do_wait();
>>>> +	    }
>>>> +	}
>>>> +    }
>>>> +
>>>> +  template<class _Tp>
>>> 
>>> s/class/template/
>>> 
>>>> +    void
>>>> +    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>>>> +    {
>>>> +      using namespace __detail;
>>>> +      auto& __w = __waiters::_S_for((void*)__addr);
>>>> +      if (!__w._M_waiting())
>>> 
>>> When __platform_wait_uses_type<_Tp> is true, will __w._M_waiting()
>>> ever be true? Won't this always return before notifying?
>>> 
>>> Is there meant to be a __waiter constructed here?
>>> 
>>>> +	return;
>>>> +
>>>> +      if constexpr (__platform_wait_uses_type<_Tp>::__value)
>>>> +	{
>>>> +	  __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..b3c83bbc70b
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/include/bits/semaphore_base.h
>>>> @@ -0,0 +1,270 @@
>>>> +// -*- 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.h
>>> 
>>> Should be bits/semaphore_base.h
>>> 
>>>> + *  This is an internal header file, included by other library headers.
>>>> + *  Do not attempt to use it directly. @headername{atomic}
>>> 
>>> Should be @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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
>>>> +#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>>>> +#include <semaphore.h>
>>>> +#endif
>>>> +
>>>> +#include <chrono>
>>>> +#include <type_traits>
>>>> +#include <limits>
>>> 
>>> <ext/numeric_traits.h> is much smaller than <limits> and should be
>>> used for limits of integer types. (I recently added
>>> <bits/int_limits.h> too but that was a mistake that I need to fix).
>>> 
>>> 
>>>> +namespace std _GLIBCXX_VISIBILITY(default)
>>>> +{
>>>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>> +
>>>> +#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>>> +  template<ptrdiff_t __least_max_t>
>>> 
>>> __least_max_t isn't a type so shouldn't have the _t suffix.
>>> 
>>>> +    struct __platform_semaphore
>>>> +    {
>>>> +      using __clock_t = chrono::system_clock;
>>>> +
>>>> +      __platform_semaphore(ptrdiff_t __count) noexcept
>>> 
>>> Should this constructor be explicit?
>>> 
>>>> +      {
>>>> +	static_assert( __least_max_t <= SEM_VALUE_MAX, "__least_max_t > SEM_VALUE_MAX");
>>> 
>>> Our static_assert messages should state the positive condition, not
>>> the negative one. So it should be "__least_max_t <= SEM_VALUE_MAX",
>>> which is what the real condition is anyway, so you might as well omit
>>> the string literal.
>>> 
>>>> +	auto __e = sem_init(&_M_semaphore, 0, __count);
>>>> +	if (__e)
>>>> +	  std::terminate();
>>>> +      }
>>>> +
>>>> +      ~__platform_semaphore()
>>>> +      {
>>>> +	auto __e = sem_destroy(&_M_semaphore);
>>>> +	if (__e)
>>>> +	  std::terminate();
>>>> +      }
>>>> +
>>>> +      _GLIBCXX_ALWAYS_INLINE void
>>>> +      acquire() noexcept
>>>> +      {
>>>> +	auto __err = sem_wait(&_M_semaphore);
>>>> +	if (__err)
>>>> +	  std::terminate();
>>>> +      }
>>>> +
>>>> +      template<typename _Duration>
>>>> +	_GLIBCXX_ALWAYS_INLINE bool
>>> 
>>> Do we really need this to be always_inline?
>>> 
>>>> +	__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())
>>>> +	  };
>>>> +
>>>> +	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>>>> +	  if (__err && (errno == ETIMEDOUT))
>>>> +	      return false;
>>>> +	  else if (__err)
>>>> +	      std::terminate();
>>>> +	  return true;
>>>> +	}
>>>> +
>>>> +      template<typename _Clock, typename _Duration>
>>>> +	_GLIBCXX_ALWAYS_INLINE bool
>>> 
>>> always_inline?
>>> 
>>>> +	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>>>> +	{
>>>> +	  if constexpr (std::is_same<__clock_t, _Clock>::value)
>>> 
>>> is_same_v
>>> 
>>>> +	    {
>>>> +	      return __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 (__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
>>>> +	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>>>> +	{ return try_acquire_until(__clock_t::now() + __rtime); }
>>>> +
>>>> +      template<typename _Clock, typename _Duration>
>>>> +	_GLIBCXX_ALWAYS_INLINE void
>>>> +	release(ptrdiff_t __update) noexcept
>>>> +	{
>>>> +	  do
>>>> +	    {
>>>> +	      auto __err = sem_post(&_M_semaphore);
>>>> +	      if (__err)
>>>> +		std::terminate();
>>>> +	    } while (--__update);
>>>> +	}
>>>> +
>>>> +      private:
>>>> +	sem_t _M_semaphore;
>>>> +      };
>>>> +#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>>> +
>>>> +    template<typename _Tp>
>>>> +      struct __atomic_semaphore
>>>> +      {
>>>> +	static constexpr size_t _S_alignment = __alignof__(_Tp);
>>>> +
>>>> +	__atomic_semaphore(_Tp __count)
>>> 
>>> Should this be explicit?
>>> 
>>>> +	  : _M_a(__count)
>>>> +	{ }
>>>> +
>>>> +	_GLIBCXX_ALWAYS_INLINE void
>>>> +	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
>>>> +	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
>>>> +	  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
>>>> +	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
>>>> +      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(_S_alignment) _Tp _M_a;
>>> 
>>> Could this just use alignas(__alignof__(_Tp)) _Tp here? There's no
>>> need for the _S_alignment constant if it's only used in one place.
>>> 
>>>> +    };
>>>> +
>>>> +#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
>>>> +  template<ptrdiff_t __least_max_t>
>>> 
>>> Rename __least_max_t here too.
>>> 
>>>> +    using __semaphore_base = __platform_semaphore<__least_max_t>;
>>>> +#else
>>>> +#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>>> +  template<ptrdiff_t __least_max_t>
>>>> +    using __semaphore_base = std::conditional<(__least_max_t > 0
>>> 
>>> This should use conditional_t<> not conditional<>::type.
>>> 
>>> The least-max_value can't be negative. If it's zero, can't we use a
>>> futex or semaphore? So the '__least_max_t > 0' condition is wrong?
>>> 
>>>> +					      && __least_max_t < std::numeric_limits<__detail::__platform_wait_t>::max()),
>>> 
>>> Should that be <= rather than < ?
>>> 
>>>> +					      __atomic_semaphore<__detail::__platform_wait_t>,
>>>> +					      __atomic_semaphore<ptrdiff_t>>::type;
>>>> +				            // __platform_semaphore
>>>> +#  else
>>>> +#    ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>> 
>>> Please use '#elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE' here to avoid
>>> an extra level of #if nesting.
>>> 
>>>> +  template<ptrdiff_t __least_max_t>
>>>> +    using __semaphore_base = std::conditional<(__least_max_t > 0 && __least_max_t <= SEM_VALUE_MAX),
>>>> +					      __platform_semaphore<__least_max_t>,
>>>> +					      __atomic_semaphore<ptrdiff_t>>::type;
>>>> +#    else
>>>> +  template<ptrdiff_t __least_max_t>
>>>> +    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>>>> +#    endif
>>>> +#  endif
>>>> +#endif
>>>> +
>>>> +_GLIBCXX_END_NAMESPACE_VERSION
>>>> +} // namespace std
>>>> +
>>>> +#endif
>>>> diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>>>> index a455286a784..3f18774031d 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
>>>> @@ -352,6 +365,19 @@ _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) noexcept
>>>> +    { _M_i.wait(__old, __m); }
>>>> +
>>>> +    // TODO add const volatile overload
>>>> +
>>>> +    void notify_one() const noexcept
>>>> +    { _M_i.notify_one(); }
>>>> +
>>>> +    void notify_all() const noexcept
>>>> +    { _M_i.notify_all(); }
>>>> +#endif
>>>> +
>>>>   };
>>>> #undef _GLIBCXX20_INIT
>>>> 
>>>> @@ -590,6 +616,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
>>>> @@ -1342,6 +1380,29 @@ _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..0099877416e
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/include/std/latch
>>>> @@ -0,0 +1,91 @@
>>>> +//<latch> -*- C++ -*-
>>> 
>>> A space before <latch>.
>>> 
>>>> +
>>>> +// 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.
>>> 
>>> Align "This" with "@file" here.
>>> 
>>>> + */
>>>> +
>>>> +#ifndef _GLIBCXX_LATCH
>>>> +#define _GLIBCXX_LATCH
>>>> +
>>>> +#pragma GCC system_header
>>>> +
>>>> +#if __cplusplus > 201703L
>>>> +#define __cpp_lib_latch 201907L
>>>> +
>>>> +#include <bits/atomic_base.h>
>>>> +#include <limits>
>>> 
>>> Use <ext/numeric_traits.h> here too.
>>> 
>>>> +namespace std _GLIBCXX_VISIBILITY(default)
>>>> +{
>>>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>> +
>>>> +  class latch
>>>> +  {
>>>> +    static constexpr size_t _S_alignment = __alignof__(ptrdiff_t);
>>>> +  public:
>>>> +    static constexpr
>>>> +    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
>>>> +    max() noexcept
>>>> +    { return numeric_limits<ptrdiff_t>::max(); }
>>>> +
>>>> +    constexpr explicit latch(ptrdiff_t __expected) : _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(_S_alignment) ptrdiff_t _M_a;
>>> 
>>> Just use __alignof__ directly here and get rid of _S_alignment?
>>> 
>>>> +  };
>>>> +_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..b51940b46ac
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/include/std/semaphore
>>>> @@ -0,0 +1,81 @@
>>>> +//<semaphore> -*- C++ -*-
>>> 
>>> A space before <semaphore>.
>>> 
>>>> +
>>>> +// 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.
>>> 
>>> Align "This" with "@file" here.
>>> 
>>>> + */
>>>> +
>>>> +#ifndef _GLIBCXX_SEMAPHORE
>>>> +#define _GLIBCXX_SEMAPHORE
>>>> +
>>>> +#pragma GCC system_header
>>>> +
>>>> +#if __cplusplus > 201703L
>>>> +#define __cpp_lib_semaphore 201907L
>>>> +#include <bits/semaphore_base.h>
>>>> +
>>>> +namespace std _GLIBCXX_VISIBILITY(default)
>>>> +{
>>>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>> +
>>>> +  template<ptrdiff_t __least_max_value = std::numeric_limits<ptrdiff_t>::max()>
>>>> +    class counting_semaphore
>>>> +    {
>>> 
>>> I don't see a static_assert making it ill-formed to use a negative
>>> value for __least_max_value. Is that enforced somewhere else?
>>> 
>>> The standard says it's ill-formed, so we should also have a _neg.cc
>>> test checking that we reject it.
>>> 
>>>> +      __semaphore_base<__least_max_value> _M_sem;
>>> 
>>> Blank line after this please.
>>> 
>>>> +    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)
>>>> +      { _M_sem.release(__update); }
>>>> +
>>>> +      void acquire()
>>>> +      { _M_sem.acquire(); }
>>>> +
>>>> +      bool try_acquire() noexcept
>>>> +      { return _M_sem.try_acquire(); }
>>>> +
>>>> +      template<class _Rep, class _Period>
>>> 
>>> s/class/template/
>>> 
>>>> +	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
>>>> +	{ return _M_sem.try_acquire_for(__rel_time); }
>>>> +
>>>> +      template<class _Clock, class _Duration>
>>> 
>>> s/class/template/
>>> 
>>>> +	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
>>>> +	{ return _M_sem.try_acquire_until(__abs_time); }
>>>> +    };
>>>> +
>>>> + 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 c3a5bd26e63..390990282b0 100644
>>>> --- a/libstdc++-v3/include/std/version
>>>> +++ b/libstdc++-v3/include/std/version
>>>> @@ -188,6 +188,8 @@
>>>> #endif
>>>> #define __cpp_lib_type_identity 201806L
>>>> #define __cpp_lib_unwrap_ref 201811L
>>>> +#define __cpp_lib_semaphore 201907L
>>>> +#define __cpp_lib_latch 201907L
>>> 
>>> These features aren't supported in a freestanding implementation, so
>>> should be in the #if _GLIBCXX_HOSTED block (and the macros should be
>>> in alphabetical order).
>>> 
>>>> 
>>>> #if _GLIBCXX_HOSTED
>>>> #undef __cpp_lib_array_constexpr
>>>> 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" }
>>> 
>>> Use { dg-add-options libatomic } instead of adding -latomic -L...
>> 
> 


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] Add C++2a synchronization support
  2020-05-23 22:52     ` Thomas Rodgers
  2020-05-24 17:41       ` Thomas Rodgers
@ 2020-06-06  0:29       ` Thomas Rodgers
  2020-07-08 16:43         ` Jonathan Wakely
  2020-08-03 14:09         ` Jonathan Wakely
  1 sibling, 2 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-06-06  0:29 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers, Thomas Rodgers

Add support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
	(__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.h: New File.
        * 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_futex.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       | 161 +++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 282 +++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 291 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 272 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  86 ++++++
 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.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 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          |  28 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_futex.cc |  51 +++
 .../30_threads/semaphore/try_acquire_posix.cc | 169 ++++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 27 files changed, 2291 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.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/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_futex.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 80aeb3f8959..b3ac1a3365f 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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 3b66b040976..68d9e7e3756 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;
@@ -562,6 +565,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
@@ -823,6 +851,30 @@ _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
@@ -911,6 +963,32 @@ _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
@@ -1164,6 +1242,23 @@ _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
@@ -1301,6 +1396,22 @@ _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); }
+
     private:
       _Tp* _M_ptr;
     };
@@ -1396,6 +1507,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1551,6 +1678,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1660,6 +1803,22 @@ _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); }
+
       _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..adef80aca61
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,282 @@
+// -*- 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
+    enum
+    {
+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+      __futex_bitset_match_any = 0xffffffff
+    };
+
+    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, __futex_wait_bitset_private, __val, &__rt,
+			    nullptr, __futex_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 (std::is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __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 (__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 (__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 (__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 (__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..92c1e2526ed
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,291 @@
+// -*- 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
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// 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;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__numeric_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
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __futex_private_flag = 128,
+#else
+      __futex_private_flag = 0,
+#endif
+      __futex_wait = 0,
+      __futex_wake = 1,
+      __futex_wait_bitset = 9,
+      __futex_wake_bitset = 10,
+      __futex_wait_private = __futex_wait | __futex_private_flag,
+      __futex_wake_private = __futex_wake | __futex_private_flag
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+    {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && !(errno == EINTR || errno == EAGAIN))
+	 std::terminate();
+    }
+
+    void
+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+    {
+      syscall (SYS_futex, __addr, __futex_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(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((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 < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < _GLIBCXX_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((__platform_wait_t*)(void*) __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..f0c4235d91c
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,272 @@
+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    struct __platform_semaphore
+    {
+      using __clock_t = chrono::system_clock;
+
+      explicit __platform_semaphore(ptrdiff_t __count) noexcept
+      {
+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");
+	auto __e = sem_init(&_M_semaphore, 0, __count);
+	if (__e)
+	  std::terminate();
+      }
+
+      ~__platform_semaphore()
+      {
+	auto __e = sem_destroy(&_M_semaphore);
+	if (__e)
+	  std::terminate();
+      }
+
+      _GLIBCXX_ALWAYS_INLINE void
+      acquire() noexcept
+      {
+	auto __err = sem_wait(&_M_semaphore);
+	if (__err)
+	  std::terminate();
+      }
+
+      template<typename _Duration>
+	bool
+	__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())
+	  };
+
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err)
+	      std::terminate();
+	  return true;
+	}
+
+      template<typename _Clock, typename _Duration>
+	bool
+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	{
+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
+	    {
+	      return __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 (__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
+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{ return try_acquire_until(__clock_t::now() + __rtime); }
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE void
+	release(ptrdiff_t __update) noexcept
+	{
+	  do
+	    {
+	      auto __err = sem_post(&_M_semaphore);
+	      if (__err)
+		std::terminate();
+	    } while (--__update);
+	}
+
+      private:
+	sem_t _M_semaphore;
+      };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	explicit __atomic_semaphore(_Tp __count)
+	  : _M_a(__count)
+	{ }
+
+	_GLIBCXX_ALWAYS_INLINE void
+	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
+	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
+	  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
+	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
+      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_REQUIRE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __platform_semaphore<__least_max_value>;
+#else
+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= __detail::__platform_wait_max_value),
+			      __atomic_semaphore<__detail::__platform_wait_t>,
+			      __atomic_semaphore<ptrdiff_t>>;
+
+// __platform_semaphore
+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= SEM_VALUE_MAX),
+			      __platform_semaphore<__least_max_value>,
+			      __atomic_semaphore<ptrdiff_t>>;
+#  else
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
+#  endif
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index a455286a784..3f18774031d 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
@@ -352,6 +365,19 @@ _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) noexcept
+    { _M_i.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_i.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_i.notify_all(); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -590,6 +616,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
@@ -1342,6 +1380,29 @@ _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..aa5299d9fdd
--- /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
+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) : _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..90cf3244647
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,86 @@
+// <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_base<__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)
+      { _M_sem.release(__update); }
+
+      void acquire()
+      { _M_sem.acquire(); }
+
+      bool try_acquire() noexcept
+      { return _M_sem.try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+	{ return _M_sem.try_acquire_for(__rel_time); }
+
+      template<class _Clock, class _Duration>
+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+	{ return _M_sem.try_acquire_until(__abs_time); }
+    };
+
+ 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 c6bde2cfbda..f09da3344f7 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -189,6 +189,8 @@
 #endif
 #define __cpp_lib_type_identity 201806L
 #define __cpp_lib_unwrap_ref 201811L
+#define __cpp_lib_semaphore 201907L
+#define __cpp_lib_latch 201907L
 
 #if _GLIBCXX_HOSTED
 #undef __cpp_lib_array_constexpr
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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..0da374ece87
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,88 @@
+// -*- 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.
+
+// 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 <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;
+
+  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_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);
+		  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>
+struct check
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+    VERIFY(check_atomic_wait_notify(a, b) == b);
+  }
+};
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..2afd19a7d14
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,56 @@
+// { 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 ()
+{
+  // 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/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..756727f33b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..10bb500d261
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019-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..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..1ac9d261ca5
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2019-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>
+
+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..d38cef86cfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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..965554a3c28
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019-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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
new file mode 100644
index 00000000000..5e05606e97f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+void test01()
+{
+  // the implementation optimizes for values of least_max_t that can fit
+  // in a futex, make sure we cover the case where least_max_t doesn't
+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
+  std::counting_semaphore<least_max_t> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  test01();
+#endif
+}
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..bf99fd3cf8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  // The implementation supports posix as an implementation strategy
+  // make sure we cover that case
+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+
+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()
+{
+  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 test03()
+{
+  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);
+}
+
+void test04()
+{
+  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 test05()
+{
+  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);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+#endif
+}
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..cc67c5c0bf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-06-06  0:29       ` Thomas Rodgers
@ 2020-07-08 16:43         ` Jonathan Wakely
  2020-08-03 14:09         ` Jonathan Wakely
  1 sibling, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-07-08 16:43 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 05/06/20 17:29 -0700, Thomas Rodgers wrote:
>Add support for -
>        atomic wait/notify_one/notify_all
>        counting_semaphore
>        binary_semaphore
>        latch
>
>        * include/Makefile.am (bits_headers): Add new header.
>	* include/Makefile.in: Regenerate.
>	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
>	(__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.h: New File.
>        * 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_futex.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.


>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index 80aeb3f8959..b3ac1a3365f 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\

Missing space before the backslash here.

> 	${std_srcdir}/limits \
> 	${std_srcdir}/list \
> 	${std_srcdir}/locale \

>--- a/libstdc++-v3/include/bits/atomic_base.h
>+++ b/libstdc++-v3/include/bits/atomic_base.h
>@@ -823,6 +851,30 @@ _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

This line should be < 80 cols.

>+      {
>@@ -911,6 +963,32 @@ _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

And this one.


>@@ -1164,6 +1242,23 @@ _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

Please add a newline after this comment.

>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -1301,6 +1396,22 @@ _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); }
>+

The TODO comment seems to be missing here, and after some notify_all
cases below. Please either add one after every non-volatile function
that's missing a volatile overload, or just put one "TODO volatile
overloads of wait and notify_{one,all}" comment in each class.

>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..adef80aca61
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>@@ -0,0 +1,282 @@
>+// -*- 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

No indentation for these BEGIN/END macros.

>+
>+  enum class __atomic_wait_status { __no_timeout, __timeout };

It seems a shame to have yet another status macro when we already have
cv_status and future_status which define enumerators with the same
names, but I suppose it's a bit confusing to reuse them. Maybe you
could just do:

using __atomic_wait_status = cv_status;

and then refer to __atomic_wait_status::no_timeout and
__atomic_wait_status::timeout, what do you think?

Even if it's a new distinct enum type, you could use no_timeout and
timeout as the enumerator names, because those are reserved names
anyway.

>+  namespace __detail
>+  {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+    enum

I think unnamed enum types in headers cause problems for modules.

>+    {
>+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
>+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
>+      __futex_bitset_match_any = 0xffffffff
>+    };
>+
>+    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, __futex_wait_bitset_private, __val, &__rt,
>+			    nullptr, __futex_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 (std::is_same_v<__platform_wait_clock_t, _Clock>)
>+	  {
>+	    return __platform_wait_until_impl(__addr, __val, __atime);

Since this is calling a free function with arguments of
program-defined types (the clock and duration), it needs to be
qualified (whereas the is_same_v above doesn't need to be qualified,
although that's harmless).

>+	  }
>+	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 (__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 (__cond_wait_until_impl(__cv, __lock, __s_atime))

__cond_wait_until_impl should be qualified.

>+	    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 (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)

Qualify.

>+		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 (__timed_waiters&) __waiters::_S_for(__t);

I'd be more comfortable with a static_cast here.

>+      }
>+    };
>+  } // 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..92c1e2526ed
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>@@ -0,0 +1,291 @@
>+// -*- 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
>+
>+#define _GLIBCXX_SPIN_COUNT_1 16
>+#define _GLIBCXX_SPIN_COUNT_2 12
>+

Yuck, do these have to be macros?

>+// 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;
>+
>+    inline constexpr
>+    auto __platform_wait_max_value =
>+		__gnu_cxx::__numeric_traits<__platform_wait_t>::__max;

You can usee the new __gnu_cxx::__int_traits alias here, since you
know __platform_wait_t is an integer, not a floating-point type. That
alias just saves instantiating __numeric_traits to figure out whether
to use __numeric_traits_integer or __numeric_traits_floating.

>+
>+    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

See earlier comment about unnamed enum types.


>+    {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>+      __futex_private_flag = 128,
>+#else
>+      __futex_private_flag = 0,
>+#endif
>+      __futex_wait = 0,
>+      __futex_wake = 1,
>+      __futex_wait_bitset = 9,
>+      __futex_wake_bitset = 10,
>+      __futex_wait_private = __futex_wait | __futex_private_flag,
>+      __futex_wake_private = __futex_wake | __futex_private_flag
>+    };
>+
>+    void
>+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
>+    {
>+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
>+       if (__e && !(errno == EINTR || errno == EAGAIN))
>+	 std::terminate();
>+    }
>+
>+    void
>+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
>+    {
>+      syscall (SYS_futex, __addr, __futex_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;

Not being able to use std::condition_variable here makes me sad.

>+      __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(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((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

Should this and the identical code in <stop_token> be consolidated
somewhere?

>+    }
>+
>+    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 < _GLIBCXX_SPIN_COUNT_1; ++__i)
>+	{
>+	  if (__pred())
>+	    return true;
>+
>+	  if (__i < _GLIBCXX_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((__platform_wait_t*)(void*) __addr, __old);

This has an implicit conversion from _To to __platform_wait_t, is that
safe? Can we make it explicit with a static_cast?

>+	    }
>+	  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..f0c4235d91c
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h

I'll continue reviewing from here ASAP ...



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-06-06  0:29       ` Thomas Rodgers
  2020-07-08 16:43         ` Jonathan Wakely
@ 2020-08-03 14:09         ` Jonathan Wakely
  2020-08-03 20:19           ` Jonathan Wakely
  1 sibling, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-08-03 14:09 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 05/06/20 17:29 -0700, Thomas Rodgers wrote:
>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>new file mode 100644
>index 00000000000..f0c4235d91c
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>@@ -0,0 +1,272 @@
>+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
>+#endif
>+
>+#include <chrono>
>+#include <type_traits>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  template<ptrdiff_t __least_max_value>
>+    struct __platform_semaphore
>+    {

I think we want to delete the copy constructor and copy assignment
operator for this type and __atomic_semaphore.

>+      using __clock_t = chrono::system_clock;
>+
>+      explicit __platform_semaphore(ptrdiff_t __count) noexcept
>+      {
>+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");
>+	auto __e = sem_init(&_M_semaphore, 0, __count);
>+	if (__e)
>+	  std::terminate();

I don't think we should bother checking the return value. The failure
conditions are EINVAL if __count > SEM_VALUE_MAX, and ENOSYS if the
second argument is non-zero. Both conditions should be impossible.

>+      }
>+
>+      ~__platform_semaphore()
>+      {
>+	auto __e = sem_destroy(&_M_semaphore);
>+	if (__e)
>+	  std::terminate();

Likewise here. The only error condition is EINVAL, which is impossible
if _M_semaphore is a valid semaphore, which the constructor already
ensured.

If somehow _M_semaphore is invalid it means the user broke something
(e.g. by scribbling over *this) and we don't need to detect and handle
that case.

>+      }
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      acquire() noexcept
>+      {
>+	auto __err = sem_wait(&_M_semaphore);
>+	if (__err)
>+	  std::terminate();

What about the EINTR case where the wait is interrupted by a signal?
I think that should retry, but it shouldn't terminate.

>+      template<typename _Duration>
>+	bool
>+	__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())
>+	  };
>+
>+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>+	  if (__err && (errno == ETIMEDOUT))
>+	      return false;
>+	  else if (__err)
>+	      std::terminate();

I think this needs to handle both EINTR and EINVAL:

        EINVAL The value of abs_timeout.tv_nsecs is less than 0, or greater than or equal to 1000 million.

Alternatively, just return immediately without waiting for a time
before the epoch, i.e.  __abs_time < time_point<__clock_t>{}

Otherwise time_point(-20ns) will cause EINVAL and terminate.


>+	  return true;
>+	}
>+
>+      template<typename _Clock, typename _Duration>
>+	bool
>+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+	{
>+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
>+	    {
>+	      return __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 (__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
>+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+	{ return try_acquire_until(__clock_t::now() + __rtime); }
>+
>+      template<typename _Clock, typename _Duration>
>+	_GLIBCXX_ALWAYS_INLINE void
>+	release(ptrdiff_t __update) noexcept
>+	{
>+	  do
>+	    {
>+	      auto __err = sem_post(&_M_semaphore);
>+	      if (__err)
>+		std::terminate();
>+	    } while (--__update);
>+	}
>+
>+      private:
>+	sem_t _M_semaphore;
>+      };
>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+
>+    template<typename _Tp>
>+      struct __atomic_semaphore
>+      {

Do we want a static_assert(is_integral_v<_Tp>) or similar?

>+	explicit __atomic_semaphore(_Tp __count)

Add noexcept?

>+	  : _M_a(__count)
>+	{ }
>+
>+	_GLIBCXX_ALWAYS_INLINE void
>+	acquire() noexcept
>+	{
>+	  auto const __pred = [this]
>+	    {
>+	      auto __old = __atomic_impl::load(&this->_M_a,
>+			      memory_order::acquire);

Would it be simpler to just use a local atomic_ref to manipulate _M_a
here, and in the other members performing atomic ops on that member?

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

Strictly speaking, this __atomic_wait would violate the "all accesses
to that object shall exclusively occur through those atomic_ref
instances" rule. But we know that it's actually OK because
__atomic_wait is only performing atomic ops on the same location.

>+	}
>+
>+	bool
>+	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
>+	  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
>+	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
>+      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_REQUIRE_POSIX_SEMAPHORE

What is this case for? This macro seems to only exist for use by a
single testcase.

Is it supposed to be something users can set? If so, it needs to be
documented as ABI-breaking and as implying that counting_semaphore
cannot be use with counts higher than SEM_VALUE_MAX.

>+  template<ptrdiff_t __least_max_value>
>+    using __semaphore_base = __platform_semaphore<__least_max_value>;
>+#else
>+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+  template<ptrdiff_t __least_max_value>
>+    using __semaphore_base = conditional_t<(
>+			      __least_max_value >= 0

This condition is redundant, we already know that counting_semaphore
has checked the value is non-negative.

>+				&& __least_max_value <= __detail::__platform_wait_max_value),
>+			      __atomic_semaphore<__detail::__platform_wait_t>,
>+			      __atomic_semaphore<ptrdiff_t>>;
>+
>+// __platform_semaphore
>+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  template<ptrdiff_t __least_max_value>
>+    using __semaphore_base = conditional_t<(
>+			      __least_max_value >= 0

Redundant condition again.

>+				&& __least_max_value <= SEM_VALUE_MAX),
>+			      __platform_semaphore<__least_max_value>,
>+			      __atomic_semaphore<ptrdiff_t>>;
>+#  else
>+  template<ptrdiff_t __least_max_value>
>+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>+#  endif
>+#endif
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+
>+#endif
>diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>index a455286a784..3f18774031d 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
>@@ -352,6 +365,19 @@ _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) noexcept
>+    { _M_i.wait(__old, __m); }

This can't be right. _M_i is of type _Tp in std::atomic<_Tp>, it doesn't 
have a wait member function.

If this compiles it suggests there are no tests for these members on
the primary template, e.g. something like:

void
test01()
{
   struct S { int i; };
   std:::atomic<S> s;
   s.wait();
}

>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_i.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_i.notify_all(); }
>+#endif
>+
>     };
> #undef _GLIBCXX20_INIT
>
>@@ -590,6 +616,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
>@@ -1342,6 +1380,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 						     memory_order_seq_cst);
>     }
>
>+
>+#if __cplusplus > 201703L
>+  template<typename _Tp>
>+    inline void atomic_wait(const atomic<_Tp>* __a,

Newline after the return type.

>+	                    typename std::atomic<_Tp>::value_type __old) noexcept
>+    { __a->wait(__old); }
>+
>+  template<typename _Tp>
>+    inline void atomic_wait_explicit(const atomic<_Tp>* __a,

And here.

>+				     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..aa5299d9fdd
>--- /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
>+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t

I don't think we need _GLIBCXX_ALWAYS_INLINE here.

>+    max() noexcept
>+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
>+
>+    constexpr explicit latch(ptrdiff_t __expected) : _M_a(__expected) { }

Add noexcept.

>+
>+    ~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);

It looks like this could use atomic_ref too, although there'd be less
benefit here.

>+      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..90cf3244647
>--- /dev/null
>+++ b/libstdc++-v3/include/std/semaphore
>@@ -0,0 +1,86 @@
>+// <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, "");

Add a space before the 0. Get rid of the empty string literal.

>+
>+      __semaphore_base<__least_max_value> _M_sem;

"base" seems a bit misleading here when it's a member not a base
class. Would __semaphore_impl be better?

>+
>+    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)

We can add noexcept here, since we know neither of the
__semaphore_base types will throw. If you envision alternative
implementations in future, then it would be futureproof to use
noexcept(noexcept(_M_sem.release(1)))

>+      { _M_sem.release(__update); }
>+
>+      void acquire()

Same here.

>+      { _M_sem.acquire(); }
>+
>+      bool try_acquire() noexcept
>+      { return _M_sem.try_acquire(); }
>+
>+      template<class _Rep, class _Period>
>+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)

Newline after the return type (the line is too long otherwise).

This one can potentially throw because of the duration arithmetic on
_Rep objects.

>+	{ return _M_sem.try_acquire_for(__rel_time); }
>+
>+      template<class _Clock, class _Duration>
>+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)

Newline after the return type (I think it's still going to be too
long).

>+	{ return _M_sem.try_acquire_until(__abs_time); }
>+    };
>+
>+ 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 c6bde2cfbda..f09da3344f7 100644
>--- a/libstdc++-v3/include/std/version
>+++ b/libstdc++-v3/include/std/version
>@@ -189,6 +189,8 @@
> #endif
> #define __cpp_lib_type_identity 201806L
> #define __cpp_lib_unwrap_ref 201811L
>+#define __cpp_lib_semaphore 201907L
>+#define __cpp_lib_latch 201907L

You're adding these macros in the freestanding section, and these
aren't freestanding headers. They need to be in the _GLIBCXX_HOSTED
block, and the macros need to be in alphabetical order.

> #if _GLIBCXX_HOSTED
> #undef __cpp_lib_array_constexpr
>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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>new file mode 100644
>index 00000000000..0da374ece87
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>@@ -0,0 +1,88 @@
>+// -*- C++ -*- header.

This isn't a header. I don't think this modeline should be here.

The test seems to be missing any dg-options, target selectors etc.

>+// 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 <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;
>+
>+  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_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);
>+		  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>
>+struct check
>+{
>+  check()
>+  {
>+    Tp a = 0;
>+    Tp b = 42;
>+    VERIFY(check_wait_notify(a, b) == b);
>+    VERIFY(check_atomic_wait_notify(a, b) == b);
>+  }
>+};
>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..2afd19a7d14
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>@@ -0,0 +1,56 @@
>+// { 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 ()
>+{
>+  // 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/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..756727f33b3
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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..10bb500d261
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>@@ -0,0 +1,50 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
>+//

Just 2020.

>+// 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..b96b8a59c64
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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..1ac9d261ca5
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>@@ -0,0 +1,28 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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>
>+
>+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..d38cef86cfc
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>@@ -0,0 +1,55 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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..965554a3c28
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>@@ -0,0 +1,85 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
>new file mode 100644
>index 00000000000..5e05606e97f
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
>@@ -0,0 +1,51 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+void test01()
>+{
>+  // the implementation optimizes for values of least_max_t that can fit
>+  // in a futex, make sure we cover the case where least_max_t doesn't
>+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
>+  std::counting_semaphore<least_max_t> s(3);
>+
>+  s.acquire();
>+  VERIFY( s.try_acquire() );
>+  VERIFY( s.try_acquire() );
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+#endif
>+
>+int main()
>+{
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+  test01();
>+#endif
>+}
>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..bf99fd3cf8f
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>@@ -0,0 +1,169 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// 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>
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  // The implementation supports posix as an implementation strategy
>+  // make sure we cover that case
>+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE


This macro is defined too late to do anything. It would ned to be
defined before including <semaphore> to have any effect.

>+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()
>+{
>+  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 test03()
>+{
>+  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);
>+}
>+
>+void test04()
>+{
>+  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 test05()
>+{
>+  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);
>+}
>+#endif
>+
>+int main()
>+{
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  test01();
>+  test02();
>+  test03();
>+  test04();
>+  test05();
>+#endif
>+}
>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..cc67c5c0bf0
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>@@ -0,0 +1,94 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+  using namespace std::chrono_literals;
>+  std::counting_semaphore<10> s(2);
>+  s.acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s.try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s.try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test02()
>+{
>+  using namespace std::chrono_literals;
>+  std::binary_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( !s.try_acquire_until(at) );
>+
>+      b++;
>+      b.notify_one();
>+    }
>+
>+    a.wait(1);
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( s.try_acquire_until(at) );
>+    }
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s.acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s.release();
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+
>+int main()
>+{
>+  test01();
>+  test02();
>+}
>-- 
>2.26.2
>


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] Add C++2a synchronization support
  2020-08-03 14:09         ` Jonathan Wakely
@ 2020-08-03 20:19           ` Jonathan Wakely
  2020-09-03  0:47             ` Thomas Rodgers
  0 siblings, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-08-03 20:19 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 03/08/20 15:09 +0100, Jonathan Wakely wrote:
>On 05/06/20 17:29 -0700, Thomas Rodgers wrote:
>>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>>new file mode 100644
>>index 00000000000..f0c4235d91c
>>--- /dev/null
>>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>>@@ -0,0 +1,272 @@
>>+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
>>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>>+#include <semaphore.h>
>>+#endif
>>+
>>+#include <chrono>
>>+#include <type_traits>
>>+
>>+namespace std _GLIBCXX_VISIBILITY(default)
>>+{
>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>+
>>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>+  template<ptrdiff_t __least_max_value>
>>+    struct __platform_semaphore

Why is this a template?

It means we'll instantiate identical code for counting_semaphore<3>
and counting_semaphore<4>, but they're distinct types that will bloat
the binary.

Can't we just have a single __platform_semaphore type for all max
values, and just make sure we don't instantiate it for values larger
than SEM_VALUE_MAX?

>>+    {
>
>I think we want to delete the copy constructor and copy assignment
>operator for this type and __atomic_semaphore.
>
>>+      using __clock_t = chrono::system_clock;
>>+
>>+      explicit __platform_semaphore(ptrdiff_t __count) noexcept
>>+      {
>>+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");

I think it would be useful for __platform_semaphore to define a static
constexpr member like:

     static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;

And then __atomic_semaphore could define:

     static constexpr _Tp _S_max = __gnu_cxx::__int_traits<_Tp>::__max;

And then the alias __semaphore_base could be defined as:

#if _GLIBCXX_HAVE_LINUX_FUTEX && ! _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
   // Use futex if available and user didn't force use of POSIX:
   using __fast_semaphore_base = __atomic_semaphore<__platform_wait_t>;
#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
   // Otherwise, use POSIX if available:
   using __fast_semaphore_base = __platform_semaphore<SEM_VALUE_MAX>;
#else
// Otherwise, use atomics:
   using __fast_semaphore_base = __atomic_semaphore<ptrdiff_t>;
#endif

   template<ptrdiff_t __least_max_value>
     using __semaphore_base = conditional_t<
       __least_max_value <= __fast_semaphore_base::_S_max,
       __fast_semaphore_base, __atomic_semaphore<ptrdiff_t>;

Would that make sense?

Do the comments above reflect the intent?


>>+#ifdef _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
>
>What is this case for? This macro seems to only exist for use by a
>single testcase.
>
>Is it supposed to be something users can set? If so, it needs to be
>documented as ABI-breaking and as implying that counting_semaphore
>cannot be use with counts higher than SEM_VALUE_MAX.
>
>>+  template<ptrdiff_t __least_max_value>
>>+    using __semaphore_base = __platform_semaphore<__least_max_value>;
>>+#else
>>+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+  template<ptrdiff_t __least_max_value>
>>+    using __semaphore_base = conditional_t<(
>>+			      __least_max_value >= 0
>
>This condition is redundant, we already know that counting_semaphore
>has checked the value is non-negative.
>
>>+				&& __least_max_value <= __detail::__platform_wait_max_value),
>>+			      __atomic_semaphore<__detail::__platform_wait_t>,
>>+			      __atomic_semaphore<ptrdiff_t>>;
>>+
>>+// __platform_semaphore
>>+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
>>+  template<ptrdiff_t __least_max_value>
>>+    using __semaphore_base = conditional_t<(
>>+			      __least_max_value >= 0
>
>Redundant condition again.
>
>>+				&& __least_max_value <= SEM_VALUE_MAX),
>>+			      __platform_semaphore<__least_max_value>,
>>+			      __atomic_semaphore<ptrdiff_t>>;
>>+#  else
>>+  template<ptrdiff_t __least_max_value>
>>+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>>+#  endif
>>+#endif
>>+
>>+_GLIBCXX_END_NAMESPACE_VERSION
>>+} // namespace std
>>+
>>+#endif


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] Add C++2a synchronization support
  2020-08-03 20:19           ` Jonathan Wakely
@ 2020-09-03  0:47             ` Thomas Rodgers
  2020-09-03  0:54               ` Thomas Rodgers
  0 siblings, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-09-03  0:47 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers, Thomas Rodgers

Adds support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
	(__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/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       | 172 +++++++++-
 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 ++++
 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 ++++++
 27 files changed, 2387 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/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 1dff3862e35..ef8acd4a389 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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/Makefile.in b/libstdc++-v3/include/Makefile.in
index 16371015071..0dfb2df9ab3 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -398,6 +398,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch\
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -415,6 +416,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 \
@@ -446,6 +448,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 \
@@ -520,6 +524,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 015acef83c4..c121d993fee 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;
@@ -562,6 +565,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
@@ -823,6 +851,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
@@ -911,6 +964,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
@@ -1164,6 +1244,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
@@ -1301,6 +1399,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;
     };
@@ -1396,6 +1512,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
@@ -1551,6 +1685,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
@@ -1660,6 +1812,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 f64aff4f520..72d7769ebcf 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -214,12 +214,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/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::atomic<int> a(0);
+
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    ++a;
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] Add C++2a synchronization support
  2020-09-03  0:47             ` Thomas Rodgers
@ 2020-09-03  0:54               ` Thomas Rodgers
  2020-09-11 23:58                 ` [PATCH] libstdc++: " Thomas Rodgers
  0 siblings, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-09-03  0:54 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers, Thomas Rodgers

Note - ignore previous version of this patch, didn't filter out
Makefile.in

Adds support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
	(__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/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       | 172 +++++++++-
 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 ++++
 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 ++++++
 27 files changed, 2387 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/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 1dff3862e35..ef8acd4a389 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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 015acef83c4..c121d993fee 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;
@@ -562,6 +565,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
@@ -823,6 +851,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
@@ -911,6 +964,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
@@ -1164,6 +1244,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
@@ -1301,6 +1399,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;
     };
@@ -1396,6 +1512,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
@@ -1551,6 +1685,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
@@ -1660,6 +1812,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 f64aff4f520..72d7769ebcf 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -214,12 +214,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/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::atomic<int> a(0);
+
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    ++a;
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-03  0:54               ` Thomas Rodgers
@ 2020-09-11 23:58                 ` Thomas Rodgers
  2020-09-28 13:25                   ` Jonathan Wakely
                                     ` (2 more replies)
  0 siblings, 3 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-09-11 23:58 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers

From: Thomas Rodgers <trodgers@redhat.com>

This patch supercedes both the Add C++2a synchronization support patch
being replied to *and* the patch adding wait/notify_* to atomic_flag.

Add support for -
  * atomic_flag::wait/notify_one/notify_all
  * atomic::wait/notify_one/notify_all
  * counting_semaphore
  * binary_semaphore
  * latch

libstdc++-v3/ChangeLog:

	* include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
	(__atomic_flag::notify_one): Likewise.
	(__atomic_flag::notify_all): Likewise.
	(__atomic_base<_Itp>::wait): Likewise.
	(__atomic_base<_Itp>::notify_one): Likewise.
	(__atomic_base<_Itp>::notify_all): Likewise.
	(__atomic_base<_Ptp*>::wait): Likewise.
	(__atomic_base<_Ptp*>::notify_one): Likewise.
	(__atomic_base<_Ptp*>::notify_all): Likewise.
	(__atomic_impl::wait): Likewise.
	(__atomic_impl::notify_one): Likewise.
	(__atomic_impl::notify_all): Likewise.
	(__atomic_float<_Fp>::wait): Likewise.
	(__atomic_float<_Fp>::notify_one): Likewise.
	(__atomic_float<_Fp>::notify_all): Likewise.
	(__atomic_ref<_Tp>::wait): Likewise.
	(__atomic_ref<_Tp>::notify_one): Likewise.
	(__atomic_ref<_Tp>::notify_all): Likewise.
	(atomic_wait<_Tp>): Likewise.
	(atomic_wait_explicit<_Tp>): Likewise.
	(atomic_notify_one<_Tp>): Likewise.
	(atomic_notify_all<_Tp>): Likewise.
	* include/bits/atomic_wait.h: New file.
	* include/bits/atomic_timed_wait.h: New file.
	* include/bits/semaphore_base.h: New file.
	* include/std/atomic (atomic<bool>::wait): Define.
	(atomic<bool>::wait_one): Likewise.
	(atomic<bool>::wait_all): Likewise.
	(atomic<_Tp>::wait): Likewise.
	(atomic<_Tp>::wait_one): Likewise.
	(atomic<_Tp>::wait_all): Likewise.
	(atomic<_Tp*>::wait): Likewise.
	(atomic<_Tp*>::wait_one): Likewise.
	(atomic<_Tp*>::wait_all): Likewise.
	* include/std/latch: New file.
	* include/std/semaphore: New file.
	* include/std/version: Add __cpp_lib_semaphore and
	__cpp_lib_latch defines.
	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
	* testsuite/30_thread/semaphore/1.cc: New test.
	* testsuite/30_thread/semaphore/2.cc: Likewise.
	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
	* testsuite/30_thread/latch/1.cc: New test.
	* testsuite/30_thread/latch/2.cc: New test.
	* testsuite/30_thread/latch/3.cc: New test.
---
 libstdc++-v3/include/Makefile.am              |   5 +
 libstdc++-v3/include/Makefile.in              |   5 +
 libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  73 +++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  92 ++++++
 libstdc++-v3/include/std/version              |   2 +
 .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
 .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
 .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
 .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
 .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
 .../atomic/wait_notify/integrals.cc           |  65 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
 libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
 .../testsuite/30_threads/semaphore/1.cc       |  27 ++
 .../testsuite/30_threads/semaphore/2.cc       |  27 ++
 .../semaphore/least_max_value_neg.cc          |  30 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 28 files changed, 2471 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
 create mode 100644 libstdc++-v3/include/std/latch
 create mode 100644 libstdc++-v3/include/std/semaphore
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch \
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
 	${std_srcdir}/scoped_allocator \
+	${std_srcdir}/semaphore \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
 	${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
+	${bits_srcdir}/atomic_timed_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
 	${bits_srcdir}/regex_compiler.tcc \
 	${bits_srcdir}/regex_executor.h \
 	${bits_srcdir}/regex_executor.tcc \
+	${bits_srcdir}/semaphore_base.h \
 	${bits_srcdir}/shared_ptr.h \
 	${bits_srcdir}/shared_ptr_atomic.h \
 	${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __atomic_load(&_M_i, &__v, int(__m));
       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
     }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait(bool __old,
+	memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]()
+			 { return this->test(__m) != __old; });
+    }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+
+    // TODO add const volatile overload
 #endif // C++20
 
     _GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__int_type __old,
+	  memory_order __m = memory_order_seq_cst) const noexcept
+      {
+	std::__atomic_wait(&_M_i, __old,
+			   [__m, this, __old]
+			   { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_i, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_i, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __int_type
       fetch_add(__int_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					   int(__m1), int(__m2));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__pointer_type __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(&_M_p, __old,
+		      [__m, this, __old]()
+		      { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_p, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_p, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					 int(__success), int(__failure));
       }
 
+#if __cplusplus > 201703L
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(const _Tp* __ptr, _Val<_Tp> __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(__ptr, __old,
+	    [=]() { return load(__ptr, __m) == __old; });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, false); }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
     template<typename _Tp>
       _GLIBCXX_ALWAYS_INLINE _Tp
       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(&_M_fp); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(&_M_fp); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
     private:
       _Tp* _M_ptr;
     };
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       _GLIBCXX_ALWAYS_INLINE value_type
       fetch_add(difference_type __d,
 		memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class __atomic_wait_status { no_timeout, timeout };
+
+  namespace __detail
+  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    using __platform_wait_clock_t = chrono::steady_clock;
+
+    template<typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until_impl(__platform_wait_t* __addr,
+				 __platform_wait_t __val,
+				 const chrono::time_point<__platform_wait_clock_t,
+							  _Duration>& __atime) noexcept
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	struct timespec __rt =
+	{
+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
+	  static_cast<long>(__ns.count())
+	};
+
+	auto __e = syscall (SYS_futex, __addr,
+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+			      __val, &__rt, nullptr,
+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+	    std::terminate();
+	return (__platform_wait_clock_t::now() < __atime)
+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+      }
+
+    template<typename _Clock, typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+			    const chrono::time_point<_Clock, _Duration>& __atime)
+      {
+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __platform_wait_clock_t::time_point __s_entry =
+		    __platform_wait_clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
+		    __atomic_wait_status::no_timeout)
+	      return __atomic_wait_status::no_timeout;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    if (_Clock::now() < __atime)
+	      return __atomic_wait_status::no_timeout;
+	    return __atomic_wait_status::timeout;
+	  }
+      }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Duration>
+      __atomic_wait_status
+      __cond_wait_until_impl(__gthread_cond_t* __cv,
+	  unique_lock<mutex>& __lock,
+	  const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	__gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+			       CLOCK_MONOTONIC,
+			       &__ts);
+	return (chrono::steady_clock::now() < __atime)
+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+      }
+#endif
+
+      template<typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until_impl(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+	{
+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	  __gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	  __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+				   &__ts);
+	  return (chrono::system_clock::now() < __atime)
+		 ? __atomic_wait_status::no_timeout
+		 : __atomic_wait_status::timeout;
+	}
+
+      // return true if timeout
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+	  using __clock_t = chrono::steady_clock;
+#else
+	  using __clock_t = chrono::system_clock;
+#endif
+	  const typename _Clock::time_point __c_entry = _Clock::now();
+	  const __clock_t::time_point __s_entry = __clock_t::now();
+	  const auto __delta = __atime - __c_entry;
+	  const auto __s_atime = __s_entry + __delta;
+	  if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+	    return __atomic_wait_status::no_timeout;
+	  // We got a timeout when measured against __clock_t but
+	  // we need to check against the caller-supplied clock
+	  // to tell whether we should return a timeout.
+	  if (_Clock::now() < __atime)
+	    return __atomic_wait_status::no_timeout;
+	  return __atomic_wait_status::timeout;
+	}
+
+    struct __timed_waiters : __waiters
+    {
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	_M_do_wait_until(__platform_wait_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	  return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+	  __platform_wait_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
+		    __atomic_wait_status::timeout)
+		return __atomic_wait_status::timeout;
+
+	      __platform_wait_t __last = __cur;
+	      __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	      if (__cur < __last)
+		break; // break the loop if version overflows
+	    }
+	  return __atomic_wait_status::no_timeout;
+#endif
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+      }
+    };
+  } // namespace __detail
+
+  template<typename _Tp, typename _Pred,
+	   typename _Clock, typename _Duration>
+    bool
+    __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+			const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+      auto __version = __w._M_enter_wait();
+      do
+	{
+	  __atomic_wait_status __res;
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+					    __old,
+					    __atime);
+	    }
+	  else
+	    {
+	      __res = __w._M_do_wait_until(__version, __atime);
+	    }
+	  if (__res == __atomic_wait_status::timeout)
+	    return false;
+	}
+      while (!__pred() && __atime < _Clock::now());
+      __w._M_leave_wait();
+
+      // if timed out, return false
+      return (_Clock::now() < __atime);
+    }
+
+  template<typename _Tp, typename _Pred,
+	   typename _Rep, typename _Period>
+    bool
+    __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+		      const chrono::duration<_Rep, _Period>& __rtime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      if (!__rtime.count())
+	return false; // no rtime supplied, and spin did not acquire
+
+      using __dur = chrono::steady_clock::duration;
+      auto __reltime = chrono::duration_cast<__dur>(__rtime);
+      if (__reltime < __rtime)
+	++__reltime;
+
+
+      return __atomic_wait_until(__addr, __old, std::move(__pred),
+				 chrono::steady_clock::now() + __reltime);
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..21ec3d38c94
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,301 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    constexpr auto __atomic_spin_count_1 = 16;
+    constexpr auto __atomic_spin_count_2 = 12;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+    template<typename _Tp>
+      inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	= is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+	= false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum class __futex_wait_flags : int
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __private_flag = 128,
+#else
+      __private_flag = 0,
+#endif
+      __wait = 0,
+      __wake = 1,
+      __wait_bitset = 9,
+      __wake_bitset = 10,
+      __wait_private = __wait | __private_flag,
+      __wake_private = __wake | __private_flag,
+      __wait_bitset_private = __wait_bitset | __private_flag,
+      __wake_bitset_private = __wake_bitset | __private_flag,
+      __bitset_match_any = -1
+    };
+
+    template<typename _Tp>
+      void
+      __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+      {
+	 auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+			      static_cast<int>(__futex_wait_flags::__wait_private),
+				__val, nullptr);
+	 if (__e && !(errno == EINTR || errno == EAGAIN))
+	   std::terminate();
+      }
+
+      template<typename _Tp>
+      void
+      __platform_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	syscall (SYS_futex, static_cast<const void*>(__addr),
+		  static_cast<int>(__futex_wait_flags::__wake_private),
+		    __all ? INT_MAX : 1);
+      }
+#endif
+
+    struct __waiters
+    {
+      __platform_wait_t alignas(64) _M_ver = 0;
+      __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#  ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#  else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#  endif
+#endif
+
+      __platform_wait_t
+      _M_enter_wait() noexcept
+      {
+	__platform_wait_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(__platform_wait_t __version) noexcept
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_wait(&_M_ver, __version);
+#else
+	__platform_wait_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      std::terminate();
+	    __platform_wait_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+#endif
+      }
+
+      __platform_wait_t
+      _M_waiting() const noexcept
+	{
+	  __platform_wait_t __res;
+	  __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+	  return __res;
+	}
+
+      void
+      _M_notify(bool __all) noexcept
+      {
+	__atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_notify(&_M_ver, __all);
+#else
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+#endif
+      }
+
+      static __waiters&
+      _S_for(const void* __t)
+      {
+	const unsigned char __mask = 0xf;
+	static __waiters __w[__mask + 1];
+
+	auto __key = _Hash_impl::hash(__t) & __mask;
+	return __w[__key];
+      }
+    };
+
+    struct __waiter
+    {
+      __waiters& _M_w;
+      __platform_wait_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+	  , _M_version(_M_w._M_enter_wait())
+	{ }
+
+      ~__waiter()
+      { _M_w._M_leave_wait(); }
+
+      void _M_do_wait() noexcept
+      { _M_w._M_do_wait(_M_version); }
+    };
+
+    void
+    __thread_relax() noexcept
+    {
+#if defined __i386__ || defined __x86_64__
+      __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    void
+    __thread_yield() noexcept
+   {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+     __gthread_yield();
+#endif
+    }
+
+  } // namespace __detail
+
+  template<typename _Pred>
+    bool
+    __atomic_spin(_Pred __pred) noexcept
+    {
+      for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < __detail::__atomic_spin_count_2)
+	    __detail::__thread_relax();
+	  else
+	    __detail::__thread_yield();
+	}
+      return false;
+    }
+
+  template<typename _Tp, typename _Pred>
+    void
+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+    {
+      using namespace __detail;
+      if (__atomic_spin(__pred))
+	return;
+
+      __waiter __w(__addr);
+      while (!__pred())
+	{
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __platform_wait(__addr, __old);
+	    }
+	  else
+	    {
+	      // TODO support timed backoff when this can be moved into the lib
+	      __w._M_do_wait();
+	    }
+	}
+    }
+
+  template<typename _Tp>
+    void
+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
+    {
+      using namespace __detail;
+      auto& __w = __waiters::_S_for((void*)__addr);
+      if (!__w._M_waiting())
+	return;
+
+      if constexpr (__platform_wait_uses_type<_Tp>)
+	{
+	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	}
+      else
+	{
+	  __w._M_notify(__all);
+	}
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..ed127a7a953
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#include <iostream>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  struct __platform_semaphore
+  {
+    using __clock_t = chrono::system_clock;
+    static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+    explicit __platform_semaphore(ptrdiff_t __count) noexcept
+    {
+      sem_init(&_M_semaphore, 0, __count);
+    }
+
+    __platform_semaphore(const __platform_semaphore&) = delete;
+    __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+    ~__platform_semaphore()
+    { sem_destroy(&_M_semaphore); }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_acquire() noexcept
+    {
+      for (;;)
+	{
+	  auto __err = sem_wait(&_M_semaphore);
+	  if (__err && (errno == EINTR))
+	    continue;
+	  else if (__err)
+	    std::terminate();
+	  else
+	    break;
+	}
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_release(std::ptrdiff_t __update) noexcept
+    {
+      for(; __update != 0; --__update)
+	{
+	   auto __err = sem_post(&_M_semaphore);
+	   if (__err)
+	     std::terminate();
+	}
+    }
+
+    bool
+    _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
+    {
+
+      auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+      struct timespec __ts =
+      {
+	static_cast<std::time_t>(__s.time_since_epoch().count()),
+	static_cast<long>(__ns.count())
+      };
+
+      for (;;)
+	{
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == EINTR))
+	      continue;
+	  else if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err && (errno == EINVAL))
+	      return false; // caller supplied an invalid __atime
+	  else if (__err)
+	      std::terminate();
+	  else
+	    break;
+	}
+      return true;
+    }
+
+    template<typename _Clock, typename _Duration>
+      bool
+      _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+      {
+	if constexpr (std::is_same<__clock_t, _Clock>::value)
+	  {
+	    return _M_try_acquire_until_impl(__atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __clock_t __s_entry = __clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (_M_try_acquire_until_impl(__s_atime))
+	      return true;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    return (_Clock::now() < __atime);
+	  }
+      }
+
+    template<typename _Rep, typename _Period>
+      _GLIBCXX_ALWAYS_INLINE bool
+      _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+      { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+    private:
+      sem_t _M_semaphore;
+    };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	static_assert(std::is_integral_v<_Tp>);
+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+	explicit __atomic_semaphore(_Tp __count) noexcept
+	  : _M_a(__count)
+	{ }
+
+	__atomic_semaphore(const __atomic_semaphore&) = delete;
+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+	_GLIBCXX_ALWAYS_INLINE void
+	_M_acquire() noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_a,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return __atomic_impl::compare_exchange_strong(&this->_M_a,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	  __atomic_wait(&_M_a, __old, __pred);
+	}
+
+	bool
+	_M_try_acquire() noexcept
+	{
+	  auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+	  if (__old == 0)
+	    return false;
+
+	  return __atomic_spin([this, &__old]
+	    {
+	      return __atomic_impl::compare_exchange_weak(&this->_M_a,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    });
+	}
+
+	template<typename _Clock, typename _Duration>
+	  _GLIBCXX_ALWAYS_INLINE bool
+	  _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	  {
+	    auto const __pred = [this]
+	      {
+		auto __old = __atomic_impl::load(&this->_M_a,
+				memory_order::acquire);
+		if (__old == 0)
+		  return false;
+		return __atomic_impl::compare_exchange_strong(&this->_M_a,
+				__old, __old - 1,
+				memory_order::acquire,
+				memory_order::release);
+	      };
+
+	    auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	    return __atomic_wait_until(&_M_a, __old, __pred, __atime);
+	}
+
+      template<typename _Rep, typename _Period>
+	_GLIBCXX_ALWAYS_INLINE bool
+	_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_a,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return  __atomic_impl::compare_exchange_strong(&this->_M_a,
+			      __old, __old - 1,
+			      memory_order::acquire,
+			      memory_order::release);
+	    };
+
+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	  return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
+	}
+
+      _GLIBCXX_ALWAYS_INLINE void
+      _M_release(ptrdiff_t __update) noexcept
+      {
+	if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
+	  return;
+	if (__update > 1)
+	  __atomic_impl::notify_all(&_M_a);
+	else
+	  __atomic_impl::notify_one(&_M_a);
+      }
+
+    private:
+      alignas(__alignof__(_Tp)) _Tp _M_a;
+    };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+  // Use futex if available and didn't force use of POSIX
+  using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  using __fast_semaphore = __platform_semaphore;
+#else
+  using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+  using __semaphore_impl = conditional_t<
+		(__least_max_value > 1),
+		conditional_t<
+		    (__least_max_value <= __fast_semaphore::_S_max),
+		    __fast_semaphore,
+		    __atomic_semaphore<ptrdiff_t>>,
+		__fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..c15909d9ccb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     compare_exchange_strong(bool& __i1, bool __i2,
 		    memory_order __m = memory_order_seq_cst) volatile noexcept
     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+    { _M_base.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_base.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_base.notify_all(); }
+#endif
   };
 
 #if __cplusplus <= 201703L
@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     memory_order __m = memory_order_seq_cst) volatile noexcept
       { return compare_exchange_strong(__e, __i, __m,
                                        __cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]
+			 {
+			   const auto __v = this->load(__m);
+			   // TODO make this ignore padding bits when we can do that
+			   return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
+			 });
+    }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    void notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					    __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+    void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+    { _M_b.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_b.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_b.notify_all(); }
+#endif
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 						     memory_order_seq_cst);
     }
 
+
+#if __cplusplus > 201703L
+  template<typename _Tp>
+    inline void
+    atomic_wait(const atomic<_Tp>* __a,
+	        typename std::atomic<_Tp>::value_type __old) noexcept
+    { __a->wait(__old); }
+
+  template<typename _Tp>
+    inline void
+    atomic_wait_explicit(const atomic<_Tp>* __a,
+			 typename std::atomic<_Tp>::value_type __old,
+			 std::memory_order __m) noexcept
+    { __a->wait(__old, __m); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_one(atomic<_Tp>* __a) noexcept
+    { __a->notify_one(); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_all(atomic<_Tp>* __a) noexcept
+    { __a->notify_all(); }
+
+#endif // C++2a
+
   // Function templates for atomic_integral and atomic_pointer operations only.
   // Some operations (and, or, xor) are only available for atomic integrals,
   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..bd06db5aa7f
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,90 @@
+// <latch> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class latch
+  {
+  public:
+    static constexpr ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) noexcept
+      : _M_a(__expected) { }
+
+    ~latch() = default;
+    latch(const latch&) = delete;
+    latch& operator=(const latch&) = delete;
+
+    _GLIBCXX_ALWAYS_INLINE void
+    count_down(ptrdiff_t __update = 1)
+    {
+      auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
+      if (__old == __update)
+	__atomic_impl::notify_all(&_M_a);
+    }
+
+    _GLIBCXX_ALWAYS_INLINE bool
+    try_wait() const noexcept
+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait() const
+    {
+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+      __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    arrive_and_wait(ptrdiff_t __update = 1)
+    {
+      count_down();
+      wait();
+    }
+
+  private:
+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+  };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..865d6c4aecb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<ptrdiff_t __least_max_value =
+			__gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
+    class counting_semaphore
+    {
+      static_assert(__least_max_value >= 0);
+
+      __semaphore_impl<__least_max_value> _M_sem;
+
+    public:
+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
+	: _M_sem(__desired)
+      { }
+
+      ~counting_semaphore() = default;
+
+      counting_semaphore(const counting_semaphore&) = delete;
+      counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+      static constexpr ptrdiff_t
+      max() noexcept
+      { return __least_max_value; }
+
+      void
+      release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+      { _M_sem._M_release(__update); }
+
+      void
+      acquire() noexcept(noexcept(_M_sem._M_acquire()))
+      { _M_sem._M_acquire(); }
+
+      bool
+      try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+      { return _M_sem._M_try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool
+	try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+	{ return _M_sem._M_try_acquire_for(__rtime); }
+
+      template<class _Clock, class _Dur>
+	bool
+	try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+	{ return _M_sem._M_try_acquire_until(__atime); }
+    };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..b9c7c6c62a8 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,12 +216,14 @@
 #ifdef _GLIBCXX_HAS_GTHREADS
 # define __cpp_lib_jthread 201911L
 #endif
+#define __cpp_lib_latch 201907L
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
 #define __cpp_lib_polymorphic_allocator 201902L
 #if __cpp_lib_concepts
 # define __cpp_lib_ranges 201911L
 #endif
+#define __cpp_lib_semaphore 201907L
 #define __cpp_lib_shift 201806L
 #define __cpp_lib_span 202002L
 #define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  Tp aa = val1;
+  std::atomic_ref<Tp> a(aa);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp,
+	 bool = std::is_integral_v<Tp>
+	 || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+  check(Tp b)
+  {
+    Tp a;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+struct foo
+{
+  long a = 0;
+  long b = 0;
+
+  foo& operator=(foo const&) = default;
+
+  friend bool
+  operator==(foo const& rhs, foo const& lhs)
+  { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+  check<long>();
+  check<double>();
+  check<foo>({42, 48});
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..b9fc063c66f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<bool> a(false);
+  std::atomic<bool> b(false);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+		  if (a.load())
+                  {
+		    b.store(true);
+                  }
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(true);
+  a.notify_one();
+  t.join();
+  VERIFY( b.load() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
new file mode 100644
index 00000000000..1d032085752
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+int
+main ()
+{
+  check<float> f;
+  check<double> d;
+  check<long double> l;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..d15b9c86ae6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+int
+main ()
+{
+  struct S{ int i; };
+  check<S> check_s{S{0},S{42}};
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,160 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+  check(Tp a = 0, Tp b = 42)
+  {
+    if constexpr (std::equality_comparable<Tp>)
+    {
+      VERIFY( check_wait_notify(a, b) == b);
+      VERIFY( check_atomic_wait_notify(a, b) == b);
+    }
+    else
+    {
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+      }
+
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_atomic_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+      }
+    }
+  }
+};
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
new file mode 100644
index 00000000000..115cb79a040
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+void
+test01()
+{
+  struct S{ int i; };
+  std::atomic<S> s;
+
+  s.wait(S{42});
+}
+
+int
+main ()
+{
+  // check<bool> bb;
+  check<char> ch;
+  check<signed char> sch;
+  check<unsigned char> uch;
+  check<short> s;
+  check<unsigned short> us;
+  check<int> i;
+  check<unsigned int> ui;
+  check<long> l;
+  check<unsigned long> ul;
+  check<long long> ll;
+  check<unsigned long long> ull;
+
+  check<wchar_t> wch;
+  check<char8_t> ch8;
+  check<char16_t> ch16;
+  check<char32_t> ch32;
+
+  check<int8_t> i8;
+  check<int16_t> i16;
+  check<int32_t> i32;
+  check<int64_t> i64;
+
+  check<uint8_t> u8;
+  check<uint16_t> u16;
+  check<uint32_t> u32;
+  check<uint64_t> u64;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  long aa;
+  long bb;
+
+  std::atomic<long*> a(nullptr);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(nullptr);
+		  if (a.load() == &aa)
+		    a.store(&bb);
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(&aa);
+  a.notify_one();
+  t.join();
+  VERIFY( a.load() == &bb);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..6de7873ecc2
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic_flag a;
+  std::atomic_flag b;
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+                  b.test_and_set();
+                  b.notify_one();
+		});
+
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.test_and_set();
+  a.notify_one();
+  b.wait(false);
+  t.join();
+
+  VERIFY( a.test() );
+  VERIFY( b.test() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::atomic<int> a(0);
+
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    ++a;
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-11 23:58                 ` [PATCH] libstdc++: " Thomas Rodgers
@ 2020-09-28 13:25                   ` Jonathan Wakely
  2020-10-01 23:37                     ` Thomas Rodgers
  2020-09-28 13:30                   ` Jonathan Wakely
  2020-09-28 13:36                   ` Jonathan Wakely
  2 siblings, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-09-28 13:25 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This patch supercedes both the Add C++2a synchronization support patch
>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>
>Add support for -
>  * atomic_flag::wait/notify_one/notify_all
>  * atomic::wait/notify_one/notify_all
>  * counting_semaphore
>  * binary_semaphore
>  * latch
>
>libstdc++-v3/ChangeLog:
>
>	* include/Makefile.am (bits_headers): Add new header.
>	* include/Makefile.in: Regenerate.
>	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
>	(__atomic_flag::notify_one): Likewise.
>	(__atomic_flag::notify_all): Likewise.
>	(__atomic_base<_Itp>::wait): Likewise.
>	(__atomic_base<_Itp>::notify_one): Likewise.
>	(__atomic_base<_Itp>::notify_all): Likewise.
>	(__atomic_base<_Ptp*>::wait): Likewise.
>	(__atomic_base<_Ptp*>::notify_one): Likewise.
>	(__atomic_base<_Ptp*>::notify_all): Likewise.
>	(__atomic_impl::wait): Likewise.
>	(__atomic_impl::notify_one): Likewise.
>	(__atomic_impl::notify_all): Likewise.
>	(__atomic_float<_Fp>::wait): Likewise.
>	(__atomic_float<_Fp>::notify_one): Likewise.
>	(__atomic_float<_Fp>::notify_all): Likewise.
>	(__atomic_ref<_Tp>::wait): Likewise.
>	(__atomic_ref<_Tp>::notify_one): Likewise.
>	(__atomic_ref<_Tp>::notify_all): Likewise.
>	(atomic_wait<_Tp>): Likewise.
>	(atomic_wait_explicit<_Tp>): Likewise.
>	(atomic_notify_one<_Tp>): Likewise.
>	(atomic_notify_all<_Tp>): Likewise.
>	* include/bits/atomic_wait.h: New file.
>	* include/bits/atomic_timed_wait.h: New file.
>	* include/bits/semaphore_base.h: New file.
>	* include/std/atomic (atomic<bool>::wait): Define.
>	(atomic<bool>::wait_one): Likewise.
>	(atomic<bool>::wait_all): Likewise.
>	(atomic<_Tp>::wait): Likewise.
>	(atomic<_Tp>::wait_one): Likewise.
>	(atomic<_Tp>::wait_all): Likewise.
>	(atomic<_Tp*>::wait): Likewise.
>	(atomic<_Tp*>::wait_one): Likewise.
>	(atomic<_Tp*>::wait_all): Likewise.
>	* include/std/latch: New file.
>	* include/std/semaphore: New file.
>	* include/std/version: Add __cpp_lib_semaphore and
>	__cpp_lib_latch defines.
>	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
>	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
>	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
>	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
>	* testsuite/30_thread/semaphore/1.cc: New test.
>	* testsuite/30_thread/semaphore/2.cc: Likewise.
>	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
>	* testsuite/30_thread/latch/1.cc: New test.
>	* testsuite/30_thread/latch/2.cc: New test.
>	* testsuite/30_thread/latch/3.cc: New test.
>---
> libstdc++-v3/include/Makefile.am              |   5 +
> libstdc++-v3/include/Makefile.in              |   5 +
> libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
> libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
> libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
> libstdc++-v3/include/std/atomic               |  73 +++++
> libstdc++-v3/include/std/latch                |  90 ++++++
> libstdc++-v3/include/std/semaphore            |  92 ++++++
> libstdc++-v3/include/std/version              |   2 +
> .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
> .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
> .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
> .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
> .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
> .../atomic/wait_notify/integrals.cc           |  65 ++++
> .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
> .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
> libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
> libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
> libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
> .../testsuite/30_threads/semaphore/1.cc       |  27 ++
> .../testsuite/30_threads/semaphore/2.cc       |  27 ++
> .../semaphore/least_max_value_neg.cc          |  30 ++
> .../30_threads/semaphore/try_acquire.cc       |  55 ++++
> .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
> .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
> 28 files changed, 2471 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
> create mode 100644 libstdc++-v3/include/std/latch
> create mode 100644 libstdc++-v3/include/std/semaphore
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index c9df9a9d6c6..9b5b6ed0005 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -52,6 +52,7 @@ std_headers = \
> 	${std_srcdir}/iostream \
> 	${std_srcdir}/istream \
> 	${std_srcdir}/iterator \
>+	${std_srcdir}/latch \
> 	${std_srcdir}/limits \
> 	${std_srcdir}/list \
> 	${std_srcdir}/locale \
>@@ -69,6 +70,7 @@ std_headers = \
> 	${std_srcdir}/ratio \
> 	${std_srcdir}/regex \
> 	${std_srcdir}/scoped_allocator \
>+	${std_srcdir}/semaphore \
> 	${std_srcdir}/set \
> 	${std_srcdir}/shared_mutex \
> 	${std_srcdir}/span \
>@@ -101,6 +103,8 @@ bits_headers = \
> 	${bits_srcdir}/allocated_ptr.h \
> 	${bits_srcdir}/allocator.h \
> 	${bits_srcdir}/atomic_base.h \
>+	${bits_srcdir}/atomic_wait.h \
>+	${bits_srcdir}/atomic_timed_wait.h \
> 	${bits_srcdir}/atomic_futex.h \
> 	${bits_srcdir}/basic_ios.h \
> 	${bits_srcdir}/basic_ios.tcc \
>@@ -175,6 +179,7 @@ bits_headers = \
> 	${bits_srcdir}/regex_compiler.tcc \
> 	${bits_srcdir}/regex_executor.h \
> 	${bits_srcdir}/regex_executor.tcc \
>+	${bits_srcdir}/semaphore_base.h \
> 	${bits_srcdir}/shared_ptr.h \
> 	${bits_srcdir}/shared_ptr_atomic.h \
> 	${bits_srcdir}/shared_ptr_base.h \
>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>index 2cdd2bd6cae..dd4db926592 100644
>--- a/libstdc++-v3/include/bits/atomic_base.h
>+++ b/libstdc++-v3/include/bits/atomic_base.h
>@@ -37,6 +37,10 @@
> #include <bits/atomic_lockfree_defines.h>
> #include <bits/move.h>
>
>+#if __cplusplus > 201703L
>+#include <bits/atomic_wait.h>
>+#endif
>+
> #ifndef _GLIBCXX_ALWAYS_INLINE
> #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
> #endif
>@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       return __ret;
>     }
>
>-
>   // Base types for atomics.
>   template<typename _IntTp>
>     struct __atomic_base;
>@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       __atomic_load(&_M_i, &__v, int(__m));
>       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
>     }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    wait(bool __old,
>+	memory_order __m = memory_order_seq_cst) const noexcept
>+    {
>+      std::__atomic_wait(&_M_i, __old,
>+			 [__m, this, __old]()
>+			 { return this->test(__m) != __old; });
>+    }
>+
>+    // TODO add const volatile overload
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    notify_one() const noexcept
>+    { std::__atomic_notify(&_M_i, false); }
>+
>+    // TODO add const volatile overload
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    notify_all() const noexcept
>+    { std::__atomic_notify(&_M_i, true); }
>+
>+    // TODO add const volatile overload
> #endif // C++20
>
>     _GLIBCXX_ALWAYS_INLINE void
>@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__m));
>       }
>
>+#if __cplusplus > 201703L
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(__int_type __old,
>+	  memory_order __m = memory_order_seq_cst) const noexcept
>+      {
>+	std::__atomic_wait(&_M_i, __old,
>+			   [__m, this, __old]
>+			   { return this->load(__m) != __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { std::__atomic_notify(&_M_i, false); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { std::__atomic_notify(&_M_i, true); }
>+
>+      // TODO add const volatile overload
>+#endif // C++2a
>+
>       _GLIBCXX_ALWAYS_INLINE __int_type
>       fetch_add(__int_type __i,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 					   int(__m1), int(__m2));
>       }
>
>+#if __cplusplus > 201703L
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(__pointer_type __old,
>+	   memory_order __m = memory_order_seq_cst) noexcept
>+      {
>+	std::__atomic_wait(&_M_p, __old,
>+		      [__m, this, __old]()
>+		      { return this->load(__m) != __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { std::__atomic_notify(&_M_p, false); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { std::__atomic_notify(&_M_p, true); }
>+
>+      // TODO add const volatile overload
>+#endif // C++2a
>+
>       _GLIBCXX_ALWAYS_INLINE __pointer_type
>       fetch_add(ptrdiff_t __d,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 					 int(__success), int(__failure));
>       }
>
>+#if __cplusplus > 201703L
>+    template<typename _Tp>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(const _Tp* __ptr, _Val<_Tp> __old,
>+	   memory_order __m = memory_order_seq_cst) noexcept
>+      {
>+	std::__atomic_wait(__ptr, __old,
>+	    [=]() { return load(__ptr, __m) == __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+    template<typename _Tp>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one(const _Tp* __ptr) noexcept
>+      { std::__atomic_notify(__ptr, false); }
>+
>+      // TODO add const volatile overload
>+
>+    template<typename _Tp>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all(const _Tp* __ptr) noexcept
>+      { std::__atomic_notify(__ptr, true); }
>+
>+      // TODO add const volatile overload
>+#endif // C++2a
>+
>     template<typename _Tp>
>       _GLIBCXX_ALWAYS_INLINE _Tp
>       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
>@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(&_M_fp, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(&_M_fp); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(&_M_fp); }
>+
>+      // TODO add const volatile overload
>+
>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>     private:
>       _Tp* _M_ptr;
>     };
>@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>       _GLIBCXX_ALWAYS_INLINE value_type
>       fetch_add(difference_type __d,
> 		memory_order __m = memory_order_seq_cst) const noexcept
>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>new file mode 100644
>index 00000000000..2f57356b366
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>@@ -0,0 +1,281 @@
>+// -*- C++ -*- header.
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/atomic_timed_wait.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{atomic}
>+ */
>+
>+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
>+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/functional_hash.h>
>+#include <bits/atomic_wait.h>
>+
>+#include <chrono>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <sys/time.h>
>+#endif
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  enum class __atomic_wait_status { no_timeout, timeout };
>+
>+  namespace __detail
>+  {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+    using __platform_wait_clock_t = chrono::steady_clock;
>+
>+    template<typename _Duration>
>+      __atomic_wait_status
>+      __platform_wait_until_impl(__platform_wait_t* __addr,
>+				 __platform_wait_t __val,
>+				 const chrono::time_point<__platform_wait_clock_t,
>+							  _Duration>& __atime) noexcept
>+      {
>+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+	struct timespec __rt =
>+	{
>+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	  static_cast<long>(__ns.count())
>+	};
>+
>+	auto __e = syscall (SYS_futex, __addr,
>+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>+			      __val, &__rt, nullptr,
>+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
>+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>+	    std::terminate();
>+	return (__platform_wait_clock_t::now() < __atime)
>+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;

Newline before the ': __atomic_wait_status::timeout' to keep it
fitting in 80 columns.

>+      }
>+
>+    template<typename _Clock, typename _Duration>
>+      __atomic_wait_status
>+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>+			    const chrono::time_point<_Clock, _Duration>& __atime)
>+      {
>+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
>+	  {
>+	    return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);

I askjed for this to be qualified, but just __detail:: is enough, you
don't need std::__detail. That should make the line fit in 80 columns.

There are still dozens of lines that don't fit in 80 cols in this
revision of the patch.

>+	  }
>+	else
>+	  {
>+	    const typename _Clock::time_point __c_entry = _Clock::now();
>+	    const __platform_wait_clock_t::time_point __s_entry =
>+		    __platform_wait_clock_t::now();
>+	    const auto __delta = __atime - __c_entry;
>+	    const auto __s_atime = __s_entry + __delta;
>+	    if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==

Just __detail:: again for the qualification. It doesn't need to be
std::__detail::.

Line breaks should be before operators please, i.e.

    value_with_a_long_name
      == bar

or:

    long_condition
      && another_condition

It's much easier to find the operator when it's at the start of the
line, at a predictable indentation, rather than wandering off on the
right somewhere.


>+		    __atomic_wait_status::no_timeout)
>+	      return __atomic_wait_status::no_timeout;
>+
>+	    // We got a timeout when measured against __clock_t but
>+	    // we need to check against the caller-supplied clock
>+	    // to tell whether we should return a timeout.
>+	    if (_Clock::now() < __atime)
>+	      return __atomic_wait_status::no_timeout;
>+	    return __atomic_wait_status::timeout;
>+	  }
>+      }
>+#endif
>+
>+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
>+    template<typename _Duration>
>+      __atomic_wait_status
>+      __cond_wait_until_impl(__gthread_cond_t* __cv,
>+	  unique_lock<mutex>& __lock,
>+	  const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
>+      {
>+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+	__gthread_time_t __ts =
>+	  {
>+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	    static_cast<long>(__ns.count())
>+	  };
>+
>+	pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
>+			       CLOCK_MONOTONIC,
>+			       &__ts);
>+	return (chrono::steady_clock::now() < __atime)
>+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>+      }
>+#endif
>+
>+      template<typename _Duration>
>+	__atomic_wait_status
>+	__cond_wait_until_impl(__gthread_cond_t* __cv,
>+	    unique_lock<std::mutex>& __lock,
>+	    const chrono::time_point<chrono::system_clock, _Duration>& __atime)
>+	{
>+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+	  __gthread_time_t __ts =
>+	  {
>+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	    static_cast<long>(__ns.count())
>+	  };
>+
>+	  __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
>+				   &__ts);
>+	  return (chrono::system_clock::now() < __atime)
>+		 ? __atomic_wait_status::no_timeout
>+		 : __atomic_wait_status::timeout;
>+	}
>+
>+      // return true if timeout
>+      template<typename _Clock, typename _Duration>
>+	__atomic_wait_status
>+	__cond_wait_until(__gthread_cond_t* __cv,
>+	    unique_lock<std::mutex>& __lock,
>+	    const chrono::time_point<_Clock, _Duration>& __atime)
>+	{
>+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
>+	  using __clock_t = chrono::steady_clock;
>+#else
>+	  using __clock_t = chrono::system_clock;
>+#endif
>+	  const typename _Clock::time_point __c_entry = _Clock::now();
>+	  const __clock_t::time_point __s_entry = __clock_t::now();
>+	  const auto __delta = __atime - __c_entry;
>+	  const auto __s_atime = __s_entry + __delta;
>+	  if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
>+	    return __atomic_wait_status::no_timeout;
>+	  // We got a timeout when measured against __clock_t but
>+	  // we need to check against the caller-supplied clock
>+	  // to tell whether we should return a timeout.
>+	  if (_Clock::now() < __atime)
>+	    return __atomic_wait_status::no_timeout;
>+	  return __atomic_wait_status::timeout;
>+	}
>+
>+    struct __timed_waiters : __waiters
>+    {
>+      template<typename _Clock, typename _Duration>
>+	__atomic_wait_status
>+	_M_do_wait_until(__platform_wait_t __version,
>+			 const chrono::time_point<_Clock, _Duration>& __atime)
>+	{
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+	  return __platform_wait_until(&_M_ver, __version, __atime);
>+#else
>+	  __platform_wait_t __cur = 0;
>+	  __waiters::__lock_t __l(_M_mtx);
>+	  while (__cur <= __version)
>+	    {
>+	      if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
>+		    __atomic_wait_status::timeout)
>+		return __atomic_wait_status::timeout;
>+
>+	      __platform_wait_t __last = __cur;
>+	      __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
>+	      if (__cur < __last)
>+		break; // break the loop if version overflows
>+	    }
>+	  return __atomic_wait_status::no_timeout;
>+#endif
>+	}
>+
>+      static __timed_waiters&
>+      _S_timed_for(void* __t)
>+      {
>+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
>+	return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
>+      }
>+    };
>+  } // namespace __detail
>+
>+  template<typename _Tp, typename _Pred,
>+	   typename _Clock, typename _Duration>
>+    bool
>+    __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
>+			const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+    {
>+      using namespace __detail;
>+
>+      if (std::__atomic_spin(__pred))
>+	return true;
>+
>+      auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
>+      auto __version = __w._M_enter_wait();
>+      do
>+	{
>+	  __atomic_wait_status __res;
>+	  if constexpr (__platform_wait_uses_type<_Tp>)
>+	    {
>+	      __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
>+					    __old,
>+					    __atime);
>+	    }
>+	  else
>+	    {
>+	      __res = __w._M_do_wait_until(__version, __atime);
>+	    }
>+	  if (__res == __atomic_wait_status::timeout)
>+	    return false;
>+	}
>+      while (!__pred() && __atime < _Clock::now());
>+      __w._M_leave_wait();
>+
>+      // if timed out, return false
>+      return (_Clock::now() < __atime);
>+    }
>+
>+  template<typename _Tp, typename _Pred,
>+	   typename _Rep, typename _Period>
>+    bool
>+    __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
>+		      const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+    {
>+      using namespace __detail;
>+
>+      if (std::__atomic_spin(__pred))
>+	return true;
>+
>+      if (!__rtime.count())
>+	return false; // no rtime supplied, and spin did not acquire
>+
>+      using __dur = chrono::steady_clock::duration;
>+      auto __reltime = chrono::duration_cast<__dur>(__rtime);
>+      if (__reltime < __rtime)
>+	++__reltime;
>+
>+
>+      return __atomic_wait_until(__addr, __old, std::move(__pred),
>+				 chrono::steady_clock::now() + __reltime);
>+    }
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+#endif
>diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
>new file mode 100644
>index 00000000000..21ec3d38c94
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>@@ -0,0 +1,301 @@
>+// -*- C++ -*- header.
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/atomic_wait.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{atomic}
>+ */
>+
>+#ifndef _GLIBCXX_ATOMIC_WAIT_H
>+#define _GLIBCXX_ATOMIC_WAIT_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/functional_hash.h>
>+#include <bits/gthr.h>
>+#include <bits/std_mutex.h>
>+#include <bits/unique_lock.h>
>+#include <ext/numeric_traits.h>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <climits>
>+#include <unistd.h>
>+#include <syscall.h>
>+#endif
>+
>+
>+// TODO get this from Autoconf
>+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+  namespace __detail
>+  {
>+    using __platform_wait_t = int;
>+
>+    constexpr auto __atomic_spin_count_1 = 16;
>+    constexpr auto __atomic_spin_count_2 = 12;
>+
>+    inline constexpr
>+    auto __platform_wait_max_value =
>+		__gnu_cxx::__int_traits<__platform_wait_t>::__max;
>+
>+    template<typename _Tp>
>+      inline constexpr bool __platform_wait_uses_type
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+	= is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
>+#else
>+	= false;
>+#endif
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+    enum class __futex_wait_flags : int
>+    {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
>+      __private_flag = 128,
>+#else
>+      __private_flag = 0,
>+#endif
>+      __wait = 0,
>+      __wake = 1,
>+      __wait_bitset = 9,
>+      __wake_bitset = 10,
>+      __wait_private = __wait | __private_flag,
>+      __wake_private = __wake | __private_flag,
>+      __wait_bitset_private = __wait_bitset | __private_flag,
>+      __wake_bitset_private = __wake_bitset | __private_flag,
>+      __bitset_match_any = -1
>+    };
>+
>+    template<typename _Tp>
>+      void
>+      __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
>+      {
>+	 auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
>+			      static_cast<int>(__futex_wait_flags::__wait_private),
>+				__val, nullptr);
>+	 if (__e && !(errno == EINTR || errno == EAGAIN))
>+	   std::terminate();

This treats EINTR and EGAIN as a spurious wakeup, right?

So callers cannot assume that this function has actually waited for
the value to change. I'll come back to that below.


>+    struct __waiters
>+    {
>+      __platform_wait_t alignas(64) _M_ver = 0;
>+      __platform_wait_t alignas(64) _M_wait = 0;

The alignment-specifier needs to come before the type name:

a.cc:3:7: warning: attribute ignored [-Wattributes]
     3 |   int alignas(64) i = 0;
       |       ^~~~~~~
a.cc:3:7: note: an attribute that appertains to a type-specifier is ignored



>+      __platform_wait_t
>+      _M_waiting() const noexcept

Should this function return a bool?
It looks like the only caller of it just tests if it's zero.

If it means "number of waiters" rather than "there are threads
waiting" then I think it should be renamed to make that more clear
(and similarly for _M_wait, which sounds like a boolean flag not a
count).

>+	{
>+	  __platform_wait_t __res;
>+	  __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
>+	  return __res;
>+	}
>+
>+      void
>+      _M_notify(bool __all) noexcept
>+      {
>+	__atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+	__platform_notify(&_M_ver, __all);
>+#else
>+	auto __e = __gthread_cond_broadcast(&_M_cv);
>+	if (__e)
>+	  __throw_system_error(__e);

This will terminate since the function is noexcept, which is fine.
Maybe we should consistently use __throw_system_error(__e) which
allows the verbose terminate handler to print a message:

terminate called after throwing an instance of 'std::system_error'
   what():  Resource temporarily unavailable
Aborted (core dumped)

So the other places that currently call std::terminate() should maybe
change to __throw_system_error(__e). What do you think?

>+#endif
>+      }
>+
>+      static __waiters&
>+      _S_for(const void* __t)
>+      {
>+	const unsigned char __mask = 0xf;
>+	static __waiters __w[__mask + 1];
>+
>+	auto __key = _Hash_impl::hash(__t) & __mask;
>+	return __w[__key];
>+      }
>+    };
>+
>+    struct __waiter
>+    {
>+      __waiters& _M_w;
>+      __platform_wait_t _M_version;
>+
>+      template<typename _Tp>
>+	__waiter(const _Tp* __addr) noexcept
>+	  : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
>+	  , _M_version(_M_w._M_enter_wait())
>+	{ }
>+
>+      ~__waiter()
>+      { _M_w._M_leave_wait(); }
>+
>+      void _M_do_wait() noexcept
>+      { _M_w._M_do_wait(_M_version); }
>+    };
>+
>+    void
>+    __thread_relax() noexcept
>+    {
>+#if defined __i386__ || defined __x86_64__
>+      __builtin_ia32_pause();
>+#elif defined _GLIBCXX_USE_SCHED_YIELD
>+      __gthread_yield();
>+#endif
>+    }
>+
>+    void
>+    __thread_yield() noexcept
>+   {
>+#if defined _GLIBCXX_USE_SCHED_YIELD
>+     __gthread_yield();
>+#endif
>+    }
>+
>+  } // namespace __detail
>+
>+  template<typename _Pred>
>+    bool
>+    __atomic_spin(_Pred __pred) noexcept

Should this take its argument by (non-const) reference?

>+    {
>+      for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
>+	{
>+	  if (__pred())
>+	    return true;
>+
>+	  if (__i < __detail::__atomic_spin_count_2)
>+	    __detail::__thread_relax();
>+	  else
>+	    __detail::__thread_yield();
>+	}
>+      return false;
>+    }
>+
>+  template<typename _Tp, typename _Pred>
>+    void
>+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
>+    {
>+      using namespace __detail;
>+      if (__atomic_spin(__pred))
>+	return;
>+
>+      __waiter __w(__addr);
>+      while (!__pred())
>+	{
>+	  if constexpr (__platform_wait_uses_type<_Tp>)
>+	    {
>+	      __platform_wait(__addr, __old);

If this gets a spurious wakeup due to EINTR or EAGAIN then we'll loop
and test the predicate again.

>+	    }
>+	  else
>+	    {
>+	      // TODO support timed backoff when this can be moved into the lib
>+	      __w._M_do_wait();
>+	    }
>+	}
>+    }
>+
>+  template<typename _Tp>
>+    void
>+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
>+    {
>+      using namespace __detail;
>+      auto& __w = __waiters::_S_for((void*)__addr);
>+      if (!__w._M_waiting())
>+	return;
>+
>+      if constexpr (__platform_wait_uses_type<_Tp>)
>+	{
>+	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
>+	}
>+      else
>+	{
>+	  __w._M_notify(__all);
>+	}
>+    }
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+#endif
>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>new file mode 100644
>index 00000000000..ed127a7a953
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>@@ -0,0 +1,283 @@
>+// -*- C++ -*- header.
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/semaphore_base.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{semaphore}
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
>+#define _GLIBCXX_SEMAPHORE_BASE_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/atomic_base.h>
>+#include <bits/atomic_timed_wait.h>
>+
>+#if __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
>+#endif
>+
>+#include <chrono>
>+#include <type_traits>
>+
>+#include <iostream>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  struct __platform_semaphore
>+  {
>+    using __clock_t = chrono::system_clock;
>+    static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
>+
>+    explicit __platform_semaphore(ptrdiff_t __count) noexcept
>+    {
>+      sem_init(&_M_semaphore, 0, __count);
>+    }
>+
>+    __platform_semaphore(const __platform_semaphore&) = delete;
>+    __platform_semaphore& operator=(const __platform_semaphore&) = delete;
>+
>+    ~__platform_semaphore()
>+    { sem_destroy(&_M_semaphore); }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    _M_acquire() noexcept
>+    {
>+      for (;;)
>+	{
>+	  auto __err = sem_wait(&_M_semaphore);
>+	  if (__err && (errno == EINTR))
>+	    continue;
>+	  else if (__err)
>+	    std::terminate();
>+	  else
>+	    break;
>+	}
>+    }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    _M_release(std::ptrdiff_t __update) noexcept
>+    {
>+      for(; __update != 0; --__update)
>+	{
>+	   auto __err = sem_post(&_M_semaphore);
>+	   if (__err)
>+	     std::terminate();
>+	}
>+    }
>+
>+    bool
>+    _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
>+    {
>+
>+      auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+      struct timespec __ts =
>+      {
>+	static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	static_cast<long>(__ns.count())
>+      };
>+
>+      for (;;)
>+	{
>+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>+	  if (__err && (errno == EINTR))
>+	      continue;
>+	  else if (__err && (errno == ETIMEDOUT))
>+	      return false;
>+	  else if (__err && (errno == EINVAL))
>+	      return false; // caller supplied an invalid __atime
>+	  else if (__err)
>+	      std::terminate();
>+	  else
>+	    break;
>+	}
>+      return true;
>+    }
>+
>+    template<typename _Clock, typename _Duration>
>+      bool
>+      _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+      {
>+	if constexpr (std::is_same<__clock_t, _Clock>::value)
>+	  {
>+	    return _M_try_acquire_until_impl(__atime);
>+	  }
>+	else
>+	  {
>+	    const typename _Clock::time_point __c_entry = _Clock::now();
>+	    const __clock_t __s_entry = __clock_t::now();
>+	    const auto __delta = __atime - __c_entry;
>+	    const auto __s_atime = __s_entry + __delta;
>+	    if (_M_try_acquire_until_impl(__s_atime))
>+	      return true;
>+
>+	    // We got a timeout when measured against __clock_t but
>+	    // we need to check against the caller-supplied clock
>+	    // to tell whether we should return a timeout.
>+	    return (_Clock::now() < __atime);
>+	  }
>+      }
>+
>+    template<typename _Rep, typename _Period>
>+      _GLIBCXX_ALWAYS_INLINE bool
>+      _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+      { return _M_try_acquire_until(__clock_t::now() + __rtime); }
>+
>+    private:
>+      sem_t _M_semaphore;
>+    };
>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+
>+    template<typename _Tp>
>+      struct __atomic_semaphore
>+      {
>+	static_assert(std::is_integral_v<_Tp>);
>+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;

Do we need a check that ptrdiff_t can represent this value?
__atomic_semaphore<size_t> would overflow here.

>+
>+	explicit __atomic_semaphore(_Tp __count) noexcept
>+	  : _M_a(__count)
>+	{ }

This should use __glibcxx_assert to check the preconditions:

__glibcxx_assert(__count >= 0 && __count <= max());

>+
>+	__atomic_semaphore(const __atomic_semaphore&) = delete;
>+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
>+
>+	_GLIBCXX_ALWAYS_INLINE void
>+	_M_acquire() noexcept
>+	{
>+	  auto const __pred = [this]
>+	    {
>+	      auto __old = __atomic_impl::load(&this->_M_a,
>+			      memory_order::acquire);
>+	      if (__old == 0)
>+		return false;
>+	      return __atomic_impl::compare_exchange_strong(&this->_M_a,
>+			__old, __old - 1,
>+			memory_order::acquire,
>+			memory_order::release);
>+	    };
>+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+	  __atomic_wait(&_M_a, __old, __pred);
>+	}
>+
>+	bool
>+	_M_try_acquire() noexcept
>+	{
>+	  auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
>+	  if (__old == 0)
>+	    return false;
>+
>+	  return __atomic_spin([this, &__old]
>+	    {

Doesn't the check for __old==0 need to be inside the predicate?

Otherwise consider the case where _M_a=1 initially. Two threads call
try_acquire() concurrently. Both see that __old==0 is false, so both
call __atomic_spin with this CAS "predicate" (*). The first thread
replaces the value with 0, the second thread fails the CAS because the
value changed, but it replaces __old with the new value and tries
again (because __atomic_spin loops) and this time it succeeds,
changing the value to -1. The second thread should have had no effect
and returned immediately.

(*) I find it a bit disconcerting that these predicates are not const,
they modify the variable, which implies a precondition that the
predicate is never evaluated again after it returns true.

>+	      return __atomic_impl::compare_exchange_weak(&this->_M_a,
>+			__old, __old - 1,
>+			memory_order::acquire,
>+			memory_order::release);
>+	    });
>+	}
>+
>+	template<typename _Clock, typename _Duration>
>+	  _GLIBCXX_ALWAYS_INLINE bool
>+	  _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+	  {
>+	    auto const __pred = [this]
>+	      {
>+		auto __old = __atomic_impl::load(&this->_M_a,
>+				memory_order::acquire);
>+		if (__old == 0)
>+		  return false;
>+		return __atomic_impl::compare_exchange_strong(&this->_M_a,
>+				__old, __old - 1,
>+				memory_order::acquire,
>+				memory_order::release);
>+	      };
>+
>+	    auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+	    return __atomic_wait_until(&_M_a, __old, __pred, __atime);
>+	}
>+
>+      template<typename _Rep, typename _Period>
>+	_GLIBCXX_ALWAYS_INLINE bool
>+	_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+	{
>+	  auto const __pred = [this]
>+	    {
>+	      auto __old = __atomic_impl::load(&this->_M_a,
>+			      memory_order::acquire);
>+	      if (__old == 0)
>+		return false;
>+	      return  __atomic_impl::compare_exchange_strong(&this->_M_a,
>+			      __old, __old - 1,
>+			      memory_order::acquire,
>+			      memory_order::release);
>+	    };
>+
>+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+	  return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
>+	}
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      _M_release(ptrdiff_t __update) noexcept
>+      {
>+	if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
>+	  return;
>+	if (__update > 1)
>+	  __atomic_impl::notify_all(&_M_a);
>+	else
>+	  __atomic_impl::notify_one(&_M_a);
>+      }
>+
>+    private:
>+      alignas(__alignof__(_Tp)) _Tp _M_a;

I'd prefer a better name than _M_a here.

The standard calls it "counter" so _M_counter maybe?

>+    };
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE

I still don't like this macro, but nevermind.

Could you add a comment saying that the macro can be used to force the
use of POSIX sem_t but that doing so alters the ABI?

>+  // Use futex if available and didn't force use of POSIX
>+  using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
>+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  using __fast_semaphore = __platform_semaphore;
>+#else
>+  using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
>+#endif
>+
>+template<ptrdiff_t __least_max_value>
>+  using __semaphore_impl = conditional_t<
>+		(__least_max_value > 1),
>+		conditional_t<
>+		    (__least_max_value <= __fast_semaphore::_S_max),
>+		    __fast_semaphore,
>+		    __atomic_semaphore<ptrdiff_t>>,
>+		__fast_semaphore>;
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+
>+#endif
>diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>index 1a304261fe7..c15909d9ccb 100644
>--- a/libstdc++-v3/include/std/atomic
>+++ b/libstdc++-v3/include/std/atomic
>@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     compare_exchange_strong(bool& __i1, bool __i2,
> 		    memory_order __m = memory_order_seq_cst) volatile noexcept
>     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
>+
>+#if __cplusplus > 201703L
>+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
>+    { _M_base.wait(__old, __m); }
>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_base.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_base.notify_all(); }
>+#endif
>   };
>
> #if __cplusplus <= 201703L
>@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 		     memory_order __m = memory_order_seq_cst) volatile noexcept
>       { return compare_exchange_strong(__e, __i, __m,
>                                        __cmpexch_failure_order(__m)); }

Blank line here before the next member function please.

>+#if __cplusplus > 201703L
>+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+    {
>+      std::__atomic_wait(&_M_i, __old,
>+			 [__m, this, __old]
>+			 {
>+			   const auto __v = this->load(__m);
>+			   // TODO make this ignore padding bits when we can do that
>+			   return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
>+			 });
>+    }
>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { std::__atomic_notify(&_M_i, false); }
>+
>+    void notify_all() const noexcept
>+    { std::__atomic_notify(&_M_i, true); }
>+#endif
>+
>     };
> #undef _GLIBCXX20_INIT
>
>@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 					    __cmpexch_failure_order(__m));
>       }
>
>+#if __cplusplus > 201703L
>+    void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>+    { _M_b.wait(__old, __m); }
>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_b.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_b.notify_all(); }
>+#endif
>       __pointer_type
>       fetch_add(ptrdiff_t __d,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 						     memory_order_seq_cst);
>     }
>
>+
>+#if __cplusplus > 201703L
>+  template<typename _Tp>
>+    inline void
>+    atomic_wait(const atomic<_Tp>* __a,
>+	        typename std::atomic<_Tp>::value_type __old) noexcept
>+    { __a->wait(__old); }
>+
>+  template<typename _Tp>
>+    inline void
>+    atomic_wait_explicit(const atomic<_Tp>* __a,
>+			 typename std::atomic<_Tp>::value_type __old,
>+			 std::memory_order __m) noexcept
>+    { __a->wait(__old, __m); }
>+
>+  template<typename _Tp>
>+    inline void
>+    atomic_notify_one(atomic<_Tp>* __a) noexcept
>+    { __a->notify_one(); }
>+
>+  template<typename _Tp>
>+    inline void
>+    atomic_notify_all(atomic<_Tp>* __a) noexcept
>+    { __a->notify_all(); }
>+
>+#endif // C++2a
>+
>   // Function templates for atomic_integral and atomic_pointer operations only.
>   // Some operations (and, or, xor) are only available for atomic integrals,
>   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
>diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
>new file mode 100644
>index 00000000000..bd06db5aa7f
>--- /dev/null
>+++ b/libstdc++-v3/include/std/latch
>@@ -0,0 +1,90 @@
>+// <latch> -*- C++ -*-
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.	This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/latch
>+ *  This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_LATCH
>+#define _GLIBCXX_LATCH
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_latch 201907L
>+
>+#include <bits/atomic_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  class latch
>+  {
>+  public:
>+    static constexpr ptrdiff_t
>+    max() noexcept
>+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }

You can use __gnu_cxx::__int_traits<ptrdiff_t> here, since we already
know ptrdiff_t is an integer type and so don't need to do the
selection between __numeric_traits for integers or floats.

>+    constexpr explicit latch(ptrdiff_t __expected) noexcept
>+      : _M_a(__expected) { }
>+
>+    ~latch() = default;
>+    latch(const latch&) = delete;
>+    latch& operator=(const latch&) = delete;
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    count_down(ptrdiff_t __update = 1)
>+    {
>+      auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);

This line is too long,

>+      if (__old == __update)
>+	__atomic_impl::notify_all(&_M_a);
>+    }
>+
>+    _GLIBCXX_ALWAYS_INLINE bool
>+    try_wait() const noexcept
>+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    wait() const
>+    {
>+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
>+      __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });

This function is not noexcept, but it only calls noexcept functions.
That suggests either __atomic_wait should not be noexcept, or this one
could be.

>+    }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    arrive_and_wait(ptrdiff_t __update = 1)
>+    {
>+      count_down();

This needs to pass the __udpate parameter to count_down.

This suggests we're missing a test using arrive_and_wait(2) or greater
values.

>+      wait();
>+    }
>+
>+  private:
>+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
>+  };
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_LATCH
>diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
>new file mode 100644
>index 00000000000..865d6c4aecb
>--- /dev/null
>+++ b/libstdc++-v3/include/std/semaphore
>@@ -0,0 +1,92 @@
>+// <semaphore> -*- C++ -*-
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.	This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/semaphore
>+ *  This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE
>+#define _GLIBCXX_SEMAPHORE
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_semaphore 201907L
>+#include <bits/semaphore_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  template<ptrdiff_t __least_max_value =
>+			__gnu_cxx::__numeric_traits<ptrdiff_t>::__max>

This can use __gnu_cxx::__int_traits too.

>+    class counting_semaphore
>+    {
>+      static_assert(__least_max_value >= 0);
>+
>+      __semaphore_impl<__least_max_value> _M_sem;
>+
>+    public:
>+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
>+	: _M_sem(__desired)
>+      { }
>+
>+      ~counting_semaphore() = default;
>+
>+      counting_semaphore(const counting_semaphore&) = delete;
>+      counting_semaphore& operator=(const counting_semaphore&) = delete;
>+
>+      static constexpr ptrdiff_t
>+      max() noexcept
>+      { return __least_max_value; }
>+
>+      void
>+      release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
>+      { _M_sem._M_release(__update); }
>+
>+      void
>+      acquire() noexcept(noexcept(_M_sem._M_acquire()))
>+      { _M_sem._M_acquire(); }
>+
>+      bool
>+      try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
>+      { return _M_sem._M_try_acquire(); }
>+
>+      template<class _Rep, class _Period>

typename, not class

>+	bool
>+	try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
>+	{ return _M_sem._M_try_acquire_for(__rtime); }
>+
>+      template<class _Clock, class _Dur>

typename, not class

>+	bool
>+	try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
>+	{ return _M_sem._M_try_acquire_until(__atime); }
>+    };
>+
>+ using binary_semaphore = std::counting_semaphore<1>;
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_SEMAPHORE
>diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
>index d5d42ed0a72..b9c7c6c62a8 100644
>--- a/libstdc++-v3/include/std/version
>+++ b/libstdc++-v3/include/std/version
>@@ -216,12 +216,14 @@
> #ifdef _GLIBCXX_HAS_GTHREADS
> # define __cpp_lib_jthread 201911L
> #endif
>+#define __cpp_lib_latch 201907L
> #define __cpp_lib_list_remove_return_type 201806L
> #define __cpp_lib_math_constants 201907L
> #define __cpp_lib_polymorphic_allocator 201902L
> #if __cpp_lib_concepts
> # define __cpp_lib_ranges 201911L
> #endif
>+#define __cpp_lib_semaphore 201907L
> #define __cpp_lib_shift 201806L
> #define __cpp_lib_span 202002L
> #define __cpp_lib_ssize 201902L
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
>new file mode 100644
>index 00000000000..1ced9d44b20
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc

This file should be under testsuite/29_atomics/atomic_ref somewhere,
not under testsuite/29_atomics/atomic

>@@ -0,0 +1,103 @@
>+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <chrono>
>+#include <type_traits>
>+
>+#include <testsuite_hooks.h>
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  Tp aa = val1;
>+  std::atomic_ref<Tp> a(aa);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(val1);
>+		  if (a.load() != val2)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  a.notify_one();
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp,
>+	 bool = std::is_integral_v<Tp>
>+	 || std::is_floating_point_v<Tp>>
>+struct check;
>+
>+template<typename Tp>
>+struct check<Tp, true>
>+{
>+  check()
>+  {
>+    Tp a = 0;
>+    Tp b = 42;
>+    VERIFY(check_wait_notify(a, b) == b);
>+  }
>+};
>+
>+template<typename Tp>
>+struct check<Tp, false>
>+{
>+  check(Tp b)
>+  {
>+    Tp a;
>+    VERIFY(check_wait_notify(a, b) == b);
>+  }
>+};
>+
>+struct foo
>+{
>+  long a = 0;
>+  long b = 0;
>+
>+  foo& operator=(foo const&) = default;
>+
>+  friend bool
>+  operator==(foo const& rhs, foo const& lhs)
>+  { return rhs.a == lhs.a && rhs.b == lhs.b; }
>+};
>+
>+int
>+main ()
>+{
>+  check<long>();
>+  check<double>();
>+  check<foo>({42, 48});
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
>new file mode 100644
>index 00000000000..b9fc063c66f
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
>@@ -0,0 +1,59 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <type_traits>
>+#include <chrono>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main ()
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<bool> a(false);
>+  std::atomic<bool> b(false);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(false);
>+		  if (a.load())
>+                  {
>+		    b.store(true);
>+                  }
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(true);
>+  a.notify_one();
>+  t.join();
>+  VERIFY( b.load() );
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
>new file mode 100644
>index 00000000000..1d032085752
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc

And this should be under testsuite/29_atomics/atomic_float

Please take another look at the dir structure under
testsuite/29_atomics/ and locate the new tests with the relevant
types. testsuite/29_atomics/atomic/ is for the generic std::atomic
template.


>@@ -0,0 +1,32 @@
>+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include "generic.h"
>+
>+int
>+main ()
>+{
>+  check<float> f;
>+  check<double> d;
>+  check<long double> l;
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
>new file mode 100644
>index 00000000000..d15b9c86ae6
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
>@@ -0,0 +1,31 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include "generic.h"
>+
>+int
>+main ()
>+{
>+  struct S{ int i; };
>+  check<S> check_s{S{0},S{42}};
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>new file mode 100644
>index 00000000000..a319e8b60a6
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>@@ -0,0 +1,160 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <chrono>
>+#include <condition_variable>
>+#include <concepts>
>+#include <mutex>
>+#include <thread>
>+
>+#include <testsuite_hooks.h>
>+
>+#include <iostream>
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+  requires std::equality_comparable<Tp>
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<Tp> a(val1);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(val1);
>+		  if (a.load() != val2)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  a.notify_one();
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<Tp> a(val1);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(val1);
>+		  auto v = a.load();
>+		  // TODO this needs to zero padding bits when we can do that
>+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  a.notify_one();
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_atomic_wait_notify(Tp val1, Tp val2)
>+  requires std::equality_comparable<Tp>
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<Tp> a(val1);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  std::atomic_wait(&a, val1);
>+		  if (a.load() != val2)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  std::atomic_notify_one(&a);
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_atomic_wait_notify(Tp val1, Tp val2)
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<Tp> a(val1);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  std::atomic_wait(&a, val1);
>+		  auto v = a.load();
>+		  // TODO this needs to zero padding bits when we can do that
>+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  std::atomic_notify_one(&a);
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp>
>+struct check
>+{
>+  check(Tp a = 0, Tp b = 42)
>+  {
>+    if constexpr (std::equality_comparable<Tp>)
>+    {
>+      VERIFY( check_wait_notify(a, b) == b);
>+      VERIFY( check_atomic_wait_notify(a, b) == b);
>+    }
>+    else
>+    {
>+      {
>+	// TODO this needs to zero padding bits when we can do that
>+	auto v = check_wait_notify(a, b);
>+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
>+      }
>+
>+      {
>+	// TODO this needs to zero padding bits when we can do that
>+	auto v = check_atomic_wait_notify(a, b);
>+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
>+      }
>+    }
>+  }
>+};
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>new file mode 100644
>index 00000000000..115cb79a040
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>@@ -0,0 +1,65 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include "generic.h"
>+
>+void
>+test01()
>+{
>+  struct S{ int i; };
>+  std::atomic<S> s;
>+
>+  s.wait(S{42});
>+}
>+
>+int
>+main ()
>+{
>+  // check<bool> bb;
>+  check<char> ch;
>+  check<signed char> sch;
>+  check<unsigned char> uch;
>+  check<short> s;
>+  check<unsigned short> us;
>+  check<int> i;
>+  check<unsigned int> ui;
>+  check<long> l;
>+  check<unsigned long> ul;
>+  check<long long> ll;
>+  check<unsigned long long> ull;
>+
>+  check<wchar_t> wch;
>+  check<char8_t> ch8;
>+  check<char16_t> ch16;
>+  check<char32_t> ch32;
>+
>+  check<int8_t> i8;
>+  check<int16_t> i16;
>+  check<int32_t> i32;
>+  check<int64_t> i64;
>+
>+  check<uint8_t> u8;
>+  check<uint16_t> u16;
>+  check<uint32_t> u32;
>+  check<uint64_t> u64;
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>new file mode 100644
>index 00000000000..8531bb2e788
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>@@ -0,0 +1,59 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <type_traits>
>+#include <chrono>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main ()
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  long aa;
>+  long bb;
>+
>+  std::atomic<long*> a(nullptr);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(nullptr);
>+		  if (a.load() == &aa)
>+		    a.store(&bb);
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(&aa);
>+  a.notify_one();
>+  t.join();
>+  VERIFY( a.load() == &bb);
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
>new file mode 100644
>index 00000000000..6de7873ecc2
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
>@@ -0,0 +1,61 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <chrono>
>+#include <condition_variable>
>+#include <concepts>
>+#include <mutex>
>+#include <thread>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main()
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic_flag a;
>+  std::atomic_flag b;
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(false);
>+                  b.test_and_set();
>+                  b.notify_one();
>+		});
>+
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.test_and_set();
>+  a.notify_one();
>+  b.wait(false);
>+  t.join();
>+
>+  VERIFY( a.test() );
>+  VERIFY( b.test() );
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
>new file mode 100644
>index 00000000000..aa203cdf525
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <latch>
>+
>+#ifndef __cpp_lib_latch
>+# error "Feature-test macro for latch missing in <latch>"
>+#elif __cpp_lib_latch!= 201907L
>+# error "Feature-test macro for latch has wrong value in <latch>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>new file mode 100644
>index 00000000000..318a859ee21
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <version>
>+
>+#ifndef __cpp_lib_latch
>+# error "Feature-test macro for latch missing in <version>"
>+#elif __cpp_lib_latch != 201907L
>+# error "Feature-test macro for latch has wrong value in <version>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>new file mode 100644
>index 00000000000..cf1a31f996b
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>@@ -0,0 +1,50 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+//
>+#include <latch>
>+#include <atomic>
>+#include <thread>
>+#include <testsuite_hooks.h>
>+
>+int main()
>+{
>+  std::atomic<int> a(0);
>+
>+  std::latch l(3);
>+
>+  VERIFY( !l.try_wait() );
>+
>+  auto fn = [&]
>+  {
>+    ++a;
>+    l.count_down();
>+  };
>+
>+  std::thread t0(fn);
>+  std::thread t1(fn);
>+
>+  l.arrive_and_wait();
>+  t0.join();
>+  t1.join();
>+
>+  VERIFY( l.try_wait() );
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>new file mode 100644
>index 00000000000..1bbca687fc3
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <semaphore>
>+
>+#ifndef __cpp_lib_semaphore
>+# error "Feature-test macro for semaphore missing in <semaphore>"
>+#elif __cpp_lib_semaphore != 201907L
>+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>new file mode 100644
>index 00000000000..98743f5e27c
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <version>
>+
>+#ifndef __cpp_lib_semaphore
>+# error "Feature-test macro for semaphore missing in <version>"
>+#elif __cpp_lib_semaphore != 201907L
>+# error "Feature-test macro for semaphore has wrong value in <version>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>new file mode 100644
>index 00000000000..d74cfad53e9
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>@@ -0,0 +1,30 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+
>+int main()
>+{
>+  std::counting_semaphore<-1> sem(2);
>+  return 0;
>+}
>+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>new file mode 100644
>index 00000000000..25280441d07
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>@@ -0,0 +1,55 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <limits>
>+#include <cstddef>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+  std::counting_semaphore<10> s(3);
>+
>+  s.acquire();
>+  VERIFY( s.try_acquire() );
>+  VERIFY( s.try_acquire() );
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+void test02()
>+{
>+  std::binary_semaphore s(1);
>+
>+  s.acquire();
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+
>+int main()
>+{
>+  test01();
>+  test02();
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>new file mode 100644
>index 00000000000..3f450e74661
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>@@ -0,0 +1,85 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+  using namespace std::chrono_literals;
>+  std::counting_semaphore<10> s(2);
>+  s.acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s.try_acquire_for(dur) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s.try_acquire_for(dur) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test02()
>+{
>+  using namespace std::chrono_literals;
>+  std::binary_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    VERIFY( !s.try_acquire_for(dur) );
>+    b++;
>+    b.notify_one();
>+
>+    a.wait(1);
>+    VERIFY( s.try_acquire_for(dur) );
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s.acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s.release();
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+
>+int main()
>+{
>+  test01();
>+  test02();
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>new file mode 100644
>index 00000000000..13bd7487d56
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>@@ -0,0 +1,153 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+  using namespace std::chrono_literals;
>+  std::__platform_semaphore s(2);
>+  s._M_acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s._M_try_acquire_for(dur) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s._M_try_acquire_for(dur) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test02()
>+{
>+  using namespace std::chrono_literals;
>+  std::__platform_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    VERIFY( !s._M_try_acquire_for(dur) );
>+    b++;
>+    b.notify_one();
>+
>+    a.wait(1);
>+    VERIFY( s._M_try_acquire_for(dur) );
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s._M_acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s._M_release(1);
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+
>+void test03()
>+{
>+  using namespace std::chrono_literals;
>+  std::__platform_semaphore s(2);
>+  s._M_acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s._M_try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s._M_try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test04()
>+{
>+  using namespace std::chrono_literals;
>+  std::__platform_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( !s._M_try_acquire_until(at) );
>+
>+      b++;
>+      b.notify_one();
>+    }
>+
>+    a.wait(1);
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( s._M_try_acquire_until(at) );
>+    }
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s._M_acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s._M_release(1);
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+#endif
>+
>+int main()
>+{
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  test01();
>+  test02();
>+  test03();
>+  test04();
>+#endif
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>new file mode 100644
>index 00000000000..af7ab7bac39
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>@@ -0,0 +1,94 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+  using namespace std::chrono_literals;
>+  std::counting_semaphore<10> s(2);
>+  s.acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s.try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s.try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test02()
>+{
>+  using namespace std::chrono_literals;
>+  std::binary_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( !s.try_acquire_until(at) );
>+
>+      b++;
>+      b.notify_one();
>+    }
>+
>+    a.wait(1);
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( s.try_acquire_until(at) );
>+    }
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s.acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s.release();
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+
>+int main()
>+{
>+  test01();
>+  test02();
>+}
>-- 
>2.26.2
>
>


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-11 23:58                 ` [PATCH] libstdc++: " Thomas Rodgers
  2020-09-28 13:25                   ` Jonathan Wakely
@ 2020-09-28 13:30                   ` Jonathan Wakely
  2020-09-28 13:36                   ` Jonathan Wakely
  2 siblings, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-09-28 13:30 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This patch supercedes both the Add C++2a synchronization support patch
>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>
>Add support for -
>  * atomic_flag::wait/notify_one/notify_all
>  * atomic::wait/notify_one/notify_all
>  * counting_semaphore
>  * binary_semaphore
>  * latch
>
>libstdc++-v3/ChangeLog:
>
>	* include/Makefile.am (bits_headers): Add new header.
>	* include/Makefile.in: Regenerate.
>	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
>	(__atomic_flag::notify_one): Likewise.
>	(__atomic_flag::notify_all): Likewise.
>	(__atomic_base<_Itp>::wait): Likewise.
>	(__atomic_base<_Itp>::notify_one): Likewise.
>	(__atomic_base<_Itp>::notify_all): Likewise.
>	(__atomic_base<_Ptp*>::wait): Likewise.
>	(__atomic_base<_Ptp*>::notify_one): Likewise.
>	(__atomic_base<_Ptp*>::notify_all): Likewise.
>	(__atomic_impl::wait): Likewise.
>	(__atomic_impl::notify_one): Likewise.
>	(__atomic_impl::notify_all): Likewise.
>	(__atomic_float<_Fp>::wait): Likewise.
>	(__atomic_float<_Fp>::notify_one): Likewise.
>	(__atomic_float<_Fp>::notify_all): Likewise.
>	(__atomic_ref<_Tp>::wait): Likewise.
>	(__atomic_ref<_Tp>::notify_one): Likewise.
>	(__atomic_ref<_Tp>::notify_all): Likewise.
>	(atomic_wait<_Tp>): Likewise.
>	(atomic_wait_explicit<_Tp>): Likewise.
>	(atomic_notify_one<_Tp>): Likewise.
>	(atomic_notify_all<_Tp>): Likewise.
>	* include/bits/atomic_wait.h: New file.
>	* include/bits/atomic_timed_wait.h: New file.
>	* include/bits/semaphore_base.h: New file.
>	* include/std/atomic (atomic<bool>::wait): Define.
>	(atomic<bool>::wait_one): Likewise.
>	(atomic<bool>::wait_all): Likewise.
>	(atomic<_Tp>::wait): Likewise.
>	(atomic<_Tp>::wait_one): Likewise.
>	(atomic<_Tp>::wait_all): Likewise.
>	(atomic<_Tp*>::wait): Likewise.
>	(atomic<_Tp*>::wait_one): Likewise.
>	(atomic<_Tp*>::wait_all): Likewise.
>	* include/std/latch: New file.
>	* include/std/semaphore: New file.
>	* include/std/version: Add __cpp_lib_semaphore and
>	__cpp_lib_latch defines.
>	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
>	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
>	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
>	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
>	* testsuite/30_thread/semaphore/1.cc: New test.
>	* testsuite/30_thread/semaphore/2.cc: Likewise.
>	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
>	* testsuite/30_thread/latch/1.cc: New test.
>	* testsuite/30_thread/latch/2.cc: New test.
>	* testsuite/30_thread/latch/3.cc: New test.
>---
> libstdc++-v3/include/Makefile.am              |   5 +
> libstdc++-v3/include/Makefile.in              |   5 +
> libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
> libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
> libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
> libstdc++-v3/include/std/atomic               |  73 +++++
> libstdc++-v3/include/std/latch                |  90 ++++++
> libstdc++-v3/include/std/semaphore            |  92 ++++++
> libstdc++-v3/include/std/version              |   2 +
> .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
> .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
> .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
> .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
> .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
> .../atomic/wait_notify/integrals.cc           |  65 ++++
> .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
> .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
> libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
> libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
> libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
> .../testsuite/30_threads/semaphore/1.cc       |  27 ++
> .../testsuite/30_threads/semaphore/2.cc       |  27 ++
> .../semaphore/least_max_value_neg.cc          |  30 ++
> .../30_threads/semaphore/try_acquire.cc       |  55 ++++
> .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
> .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
> 28 files changed, 2471 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
> create mode 100644 libstdc++-v3/include/std/latch
> create mode 100644 libstdc++-v3/include/std/semaphore
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index c9df9a9d6c6..9b5b6ed0005 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -52,6 +52,7 @@ std_headers = \
> 	${std_srcdir}/iostream \
> 	${std_srcdir}/istream \
> 	${std_srcdir}/iterator \
>+	${std_srcdir}/latch \
> 	${std_srcdir}/limits \
> 	${std_srcdir}/list \
> 	${std_srcdir}/locale \
>@@ -69,6 +70,7 @@ std_headers = \
> 	${std_srcdir}/ratio \
> 	${std_srcdir}/regex \
> 	${std_srcdir}/scoped_allocator \
>+	${std_srcdir}/semaphore \
> 	${std_srcdir}/set \
> 	${std_srcdir}/shared_mutex \
> 	${std_srcdir}/span \
>@@ -101,6 +103,8 @@ bits_headers = \
> 	${bits_srcdir}/allocated_ptr.h \
> 	${bits_srcdir}/allocator.h \
> 	${bits_srcdir}/atomic_base.h \
>+	${bits_srcdir}/atomic_wait.h \
>+	${bits_srcdir}/atomic_timed_wait.h \
> 	${bits_srcdir}/atomic_futex.h \

These should be kept in alphabetical order.

> 	${bits_srcdir}/basic_ios.h \
> 	${bits_srcdir}/basic_ios.tcc \


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-11 23:58                 ` [PATCH] libstdc++: " Thomas Rodgers
  2020-09-28 13:25                   ` Jonathan Wakely
  2020-09-28 13:30                   ` Jonathan Wakely
@ 2020-09-28 13:36                   ` Jonathan Wakely
  2020-09-28 21:29                     ` Thomas Rodgers
  2 siblings, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-09-28 13:36 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This patch supercedes both the Add C++2a synchronization support patch
>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>
>Add support for -
>  * atomic_flag::wait/notify_one/notify_all
>  * atomic::wait/notify_one/notify_all
>  * counting_semaphore
>  * binary_semaphore
>  * latch
>
>libstdc++-v3/ChangeLog:
>
>	* include/Makefile.am (bits_headers): Add new header.
>	* include/Makefile.in: Regenerate.
>	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
>	(__atomic_flag::notify_one): Likewise.
>	(__atomic_flag::notify_all): Likewise.
>	(__atomic_base<_Itp>::wait): Likewise.
>	(__atomic_base<_Itp>::notify_one): Likewise.
>	(__atomic_base<_Itp>::notify_all): Likewise.
>	(__atomic_base<_Ptp*>::wait): Likewise.
>	(__atomic_base<_Ptp*>::notify_one): Likewise.
>	(__atomic_base<_Ptp*>::notify_all): Likewise.
>	(__atomic_impl::wait): Likewise.
>	(__atomic_impl::notify_one): Likewise.
>	(__atomic_impl::notify_all): Likewise.
>	(__atomic_float<_Fp>::wait): Likewise.
>	(__atomic_float<_Fp>::notify_one): Likewise.
>	(__atomic_float<_Fp>::notify_all): Likewise.
>	(__atomic_ref<_Tp>::wait): Likewise.
>	(__atomic_ref<_Tp>::notify_one): Likewise.
>	(__atomic_ref<_Tp>::notify_all): Likewise.
>	(atomic_wait<_Tp>): Likewise.
>	(atomic_wait_explicit<_Tp>): Likewise.
>	(atomic_notify_one<_Tp>): Likewise.
>	(atomic_notify_all<_Tp>): Likewise.
>	* include/bits/atomic_wait.h: New file.
>	* include/bits/atomic_timed_wait.h: New file.
>	* include/bits/semaphore_base.h: New file.
>	* include/std/atomic (atomic<bool>::wait): Define.
>	(atomic<bool>::wait_one): Likewise.
>	(atomic<bool>::wait_all): Likewise.
>	(atomic<_Tp>::wait): Likewise.
>	(atomic<_Tp>::wait_one): Likewise.
>	(atomic<_Tp>::wait_all): Likewise.
>	(atomic<_Tp*>::wait): Likewise.
>	(atomic<_Tp*>::wait_one): Likewise.
>	(atomic<_Tp*>::wait_all): Likewise.
>	* include/std/latch: New file.
>	* include/std/semaphore: New file.
>	* include/std/version: Add __cpp_lib_semaphore and
>	__cpp_lib_latch defines.
>	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
>	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
>	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
>	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
>	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
>	* testsuite/30_thread/semaphore/1.cc: New test.
>	* testsuite/30_thread/semaphore/2.cc: Likewise.
>	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
>	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
>	* testsuite/30_thread/latch/1.cc: New test.
>	* testsuite/30_thread/latch/2.cc: New test.
>	* testsuite/30_thread/latch/3.cc: New test.
>---
> libstdc++-v3/include/Makefile.am              |   5 +
> libstdc++-v3/include/Makefile.in              |   5 +
> libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
> libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
> libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
> libstdc++-v3/include/std/atomic               |  73 +++++
> libstdc++-v3/include/std/latch                |  90 ++++++
> libstdc++-v3/include/std/semaphore            |  92 ++++++
> libstdc++-v3/include/std/version              |   2 +
> .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
> .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
> .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
> .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
> .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
> .../atomic/wait_notify/integrals.cc           |  65 ++++
> .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
> .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
> libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
> libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
> libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
> .../testsuite/30_threads/semaphore/1.cc       |  27 ++
> .../testsuite/30_threads/semaphore/2.cc       |  27 ++
> .../semaphore/least_max_value_neg.cc          |  30 ++
> .../30_threads/semaphore/try_acquire.cc       |  55 ++++
> .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
> .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
> 28 files changed, 2471 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
> create mode 100644 libstdc++-v3/include/std/latch
> create mode 100644 libstdc++-v3/include/std/semaphore
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index c9df9a9d6c6..9b5b6ed0005 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -52,6 +52,7 @@ std_headers = \
> 	${std_srcdir}/iostream \
> 	${std_srcdir}/istream \
> 	${std_srcdir}/iterator \
>+	${std_srcdir}/latch \
> 	${std_srcdir}/limits \
> 	${std_srcdir}/list \
> 	${std_srcdir}/locale \
>@@ -69,6 +70,7 @@ std_headers = \
> 	${std_srcdir}/ratio \
> 	${std_srcdir}/regex \
> 	${std_srcdir}/scoped_allocator \
>+	${std_srcdir}/semaphore \
> 	${std_srcdir}/set \
> 	${std_srcdir}/shared_mutex \
> 	${std_srcdir}/span \
>@@ -101,6 +103,8 @@ bits_headers = \
> 	${bits_srcdir}/allocated_ptr.h \
> 	${bits_srcdir}/allocator.h \
> 	${bits_srcdir}/atomic_base.h \
>+	${bits_srcdir}/atomic_wait.h \
>+	${bits_srcdir}/atomic_timed_wait.h \
> 	${bits_srcdir}/atomic_futex.h \
> 	${bits_srcdir}/basic_ios.h \
> 	${bits_srcdir}/basic_ios.tcc \
>@@ -175,6 +179,7 @@ bits_headers = \
> 	${bits_srcdir}/regex_compiler.tcc \
> 	${bits_srcdir}/regex_executor.h \
> 	${bits_srcdir}/regex_executor.tcc \
>+	${bits_srcdir}/semaphore_base.h \
> 	${bits_srcdir}/shared_ptr.h \
> 	${bits_srcdir}/shared_ptr_atomic.h \
> 	${bits_srcdir}/shared_ptr_base.h \
>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>index 2cdd2bd6cae..dd4db926592 100644
>--- a/libstdc++-v3/include/bits/atomic_base.h
>+++ b/libstdc++-v3/include/bits/atomic_base.h
>@@ -37,6 +37,10 @@
> #include <bits/atomic_lockfree_defines.h>
> #include <bits/move.h>
>
>+#if __cplusplus > 201703L
>+#include <bits/atomic_wait.h>
>+#endif
>+
> #ifndef _GLIBCXX_ALWAYS_INLINE
> #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
> #endif
>@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       return __ret;
>     }
>
>-
>   // Base types for atomics.
>   template<typename _IntTp>
>     struct __atomic_base;
>@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       __atomic_load(&_M_i, &__v, int(__m));
>       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
>     }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    wait(bool __old,
>+	memory_order __m = memory_order_seq_cst) const noexcept
>+    {
>+      std::__atomic_wait(&_M_i, __old,
>+			 [__m, this, __old]()
>+			 { return this->test(__m) != __old; });
>+    }
>+
>+    // TODO add const volatile overload
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    notify_one() const noexcept
>+    { std::__atomic_notify(&_M_i, false); }
>+
>+    // TODO add const volatile overload
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    notify_all() const noexcept
>+    { std::__atomic_notify(&_M_i, true); }
>+
>+    // TODO add const volatile overload
> #endif // C++20
>
>     _GLIBCXX_ALWAYS_INLINE void
>@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__m));
>       }
>
>+#if __cplusplus > 201703L
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(__int_type __old,
>+	  memory_order __m = memory_order_seq_cst) const noexcept
>+      {
>+	std::__atomic_wait(&_M_i, __old,
>+			   [__m, this, __old]
>+			   { return this->load(__m) != __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { std::__atomic_notify(&_M_i, false); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { std::__atomic_notify(&_M_i, true); }
>+
>+      // TODO add const volatile overload
>+#endif // C++2a
>+
>       _GLIBCXX_ALWAYS_INLINE __int_type
>       fetch_add(__int_type __i,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 					   int(__m1), int(__m2));
>       }
>
>+#if __cplusplus > 201703L
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(__pointer_type __old,
>+	   memory_order __m = memory_order_seq_cst) noexcept
>+      {
>+	std::__atomic_wait(&_M_p, __old,
>+		      [__m, this, __old]()
>+		      { return this->load(__m) != __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { std::__atomic_notify(&_M_p, false); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { std::__atomic_notify(&_M_p, true); }
>+
>+      // TODO add const volatile overload
>+#endif // C++2a
>+
>       _GLIBCXX_ALWAYS_INLINE __pointer_type
>       fetch_add(ptrdiff_t __d,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 					 int(__success), int(__failure));
>       }
>
>+#if __cplusplus > 201703L
>+    template<typename _Tp>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(const _Tp* __ptr, _Val<_Tp> __old,
>+	   memory_order __m = memory_order_seq_cst) noexcept
>+      {
>+	std::__atomic_wait(__ptr, __old,
>+	    [=]() { return load(__ptr, __m) == __old; });
>+      }
>+
>+      // TODO add const volatile overload
>+
>+    template<typename _Tp>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one(const _Tp* __ptr) noexcept
>+      { std::__atomic_notify(__ptr, false); }
>+
>+      // TODO add const volatile overload
>+
>+    template<typename _Tp>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all(const _Tp* __ptr) noexcept
>+      { std::__atomic_notify(__ptr, true); }
>+
>+      // TODO add const volatile overload
>+#endif // C++2a
>+
>     template<typename _Tp>
>       _GLIBCXX_ALWAYS_INLINE _Tp
>       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
>@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(&_M_fp, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(&_M_fp); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(&_M_fp); }
>+
>+      // TODO add const volatile overload
>+
>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>     private:
>       _Tp* _M_ptr;
>     };
>@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>       value_type
>       fetch_add(value_type __i,
> 		memory_order __m = memory_order_seq_cst) const noexcept
>@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 				       __cmpexch_failure_order(__order));
>       }
>
>+      _GLIBCXX_ALWAYS_INLINE void
>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_one() const noexcept
>+      { __atomic_impl::notify_one(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>+      _GLIBCXX_ALWAYS_INLINE void
>+      notify_all() const noexcept
>+      { __atomic_impl::notify_all(_M_ptr); }
>+
>+      // TODO add const volatile overload
>+
>       _GLIBCXX_ALWAYS_INLINE value_type
>       fetch_add(difference_type __d,
> 		memory_order __m = memory_order_seq_cst) const noexcept
>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>new file mode 100644
>index 00000000000..2f57356b366
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>@@ -0,0 +1,281 @@
>+// -*- C++ -*- header.
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/atomic_timed_wait.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{atomic}
>+ */
>+
>+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
>+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/functional_hash.h>
>+#include <bits/atomic_wait.h>
>+
>+#include <chrono>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+#include <sys/time.h>
>+#endif
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  enum class __atomic_wait_status { no_timeout, timeout };
>+
>+  namespace __detail
>+  {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+    using __platform_wait_clock_t = chrono::steady_clock;
>+
>+    template<typename _Duration>
>+      __atomic_wait_status
>+      __platform_wait_until_impl(__platform_wait_t* __addr,
>+				 __platform_wait_t __val,
>+				 const chrono::time_point<__platform_wait_clock_t,
>+							  _Duration>& __atime) noexcept
>+      {
>+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+	struct timespec __rt =
>+	{
>+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	  static_cast<long>(__ns.count())
>+	};
>+
>+	auto __e = syscall (SYS_futex, __addr,
>+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>+			      __val, &__rt, nullptr,
>+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
>+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>+	    std::terminate();
>+	return (__platform_wait_clock_t::now() < __atime)
>+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>+      }
>+
>+    template<typename _Clock, typename _Duration>
>+      __atomic_wait_status
>+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>+			    const chrono::time_point<_Clock, _Duration>& __atime)
>+      {
>+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)

This case is impossible, since the other overload would be selected
if the clock is the __platform_wait_clock_t (unless the caller says
__platform_wait_until<__platform_wait_until> to explicitly call this
overload, but users can't call this function, and we won't do that).

>+	  {
>+	    return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
>+	  }


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-28 13:36                   ` Jonathan Wakely
@ 2020-09-28 21:29                     ` Thomas Rodgers
  2020-09-29  9:44                       ` Jonathan Wakely
  0 siblings, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-09-28 21:29 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Thomas Rodgers, gcc-patches, libstdc++


Jonathan Wakely writes:

> On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
>>From: Thomas Rodgers <trodgers@redhat.com>
>>
>>This patch supercedes both the Add C++2a synchronization support patch
>>being replied to *and* the patch adding wait/notify_* to atomic_flag.
>>
>>Add support for -
>>  * atomic_flag::wait/notify_one/notify_all
>>  * atomic::wait/notify_one/notify_all
>>  * counting_semaphore
>>  * binary_semaphore
>>  * latch
>>
>>libstdc++-v3/ChangeLog:
>>
>>	* include/Makefile.am (bits_headers): Add new header.
>>	* include/Makefile.in: Regenerate.
>>	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
>>	(__atomic_flag::notify_one): Likewise.
>>	(__atomic_flag::notify_all): Likewise.
>>	(__atomic_base<_Itp>::wait): Likewise.
>>	(__atomic_base<_Itp>::notify_one): Likewise.
>>	(__atomic_base<_Itp>::notify_all): Likewise.
>>	(__atomic_base<_Ptp*>::wait): Likewise.
>>	(__atomic_base<_Ptp*>::notify_one): Likewise.
>>	(__atomic_base<_Ptp*>::notify_all): Likewise.
>>	(__atomic_impl::wait): Likewise.
>>	(__atomic_impl::notify_one): Likewise.
>>	(__atomic_impl::notify_all): Likewise.
>>	(__atomic_float<_Fp>::wait): Likewise.
>>	(__atomic_float<_Fp>::notify_one): Likewise.
>>	(__atomic_float<_Fp>::notify_all): Likewise.
>>	(__atomic_ref<_Tp>::wait): Likewise.
>>	(__atomic_ref<_Tp>::notify_one): Likewise.
>>	(__atomic_ref<_Tp>::notify_all): Likewise.
>>	(atomic_wait<_Tp>): Likewise.
>>	(atomic_wait_explicit<_Tp>): Likewise.
>>	(atomic_notify_one<_Tp>): Likewise.
>>	(atomic_notify_all<_Tp>): Likewise.
>>	* include/bits/atomic_wait.h: New file.
>>	* include/bits/atomic_timed_wait.h: New file.
>>	* include/bits/semaphore_base.h: New file.
>>	* include/std/atomic (atomic<bool>::wait): Define.
>>	(atomic<bool>::wait_one): Likewise.
>>	(atomic<bool>::wait_all): Likewise.
>>	(atomic<_Tp>::wait): Likewise.
>>	(atomic<_Tp>::wait_one): Likewise.
>>	(atomic<_Tp>::wait_all): Likewise.
>>	(atomic<_Tp*>::wait): Likewise.
>>	(atomic<_Tp*>::wait_one): Likewise.
>>	(atomic<_Tp*>::wait_all): Likewise.
>>	* include/std/latch: New file.
>>	* include/std/semaphore: New file.
>>	* include/std/version: Add __cpp_lib_semaphore and
>>	__cpp_lib_latch defines.
>>	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
>>	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
>>	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
>>	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
>>	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
>>	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
>>	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
>>	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
>>	* testsuite/30_thread/semaphore/1.cc: New test.
>>	* testsuite/30_thread/semaphore/2.cc: Likewise.
>>	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
>>	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
>>	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
>>	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
>>	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
>>	* testsuite/30_thread/latch/1.cc: New test.
>>	* testsuite/30_thread/latch/2.cc: New test.
>>	* testsuite/30_thread/latch/3.cc: New test.
>>---
>> libstdc++-v3/include/Makefile.am              |   5 +
>> libstdc++-v3/include/Makefile.in              |   5 +
>> libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
>> libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
>> libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
>> libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
>> libstdc++-v3/include/std/atomic               |  73 +++++
>> libstdc++-v3/include/std/latch                |  90 ++++++
>> libstdc++-v3/include/std/semaphore            |  92 ++++++
>> libstdc++-v3/include/std/version              |   2 +
>> .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
>> .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
>> .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
>> .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
>> .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
>> .../atomic/wait_notify/integrals.cc           |  65 ++++
>> .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
>> .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
>> libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
>> libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
>> libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
>> .../testsuite/30_threads/semaphore/1.cc       |  27 ++
>> .../testsuite/30_threads/semaphore/2.cc       |  27 ++
>> .../semaphore/least_max_value_neg.cc          |  30 ++
>> .../30_threads/semaphore/try_acquire.cc       |  55 ++++
>> .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
>> .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
>> .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
>> 28 files changed, 2471 insertions(+), 1 deletion(-)
>> create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
>> create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
>> create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
>> create mode 100644 libstdc++-v3/include/std/latch
>> create mode 100644 libstdc++-v3/include/std/semaphore
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>> create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>> create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>>
>>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>>index c9df9a9d6c6..9b5b6ed0005 100644
>>--- a/libstdc++-v3/include/Makefile.am
>>+++ b/libstdc++-v3/include/Makefile.am
>>@@ -52,6 +52,7 @@ std_headers = \
>> 	${std_srcdir}/iostream \
>> 	${std_srcdir}/istream \
>> 	${std_srcdir}/iterator \
>>+	${std_srcdir}/latch \
>> 	${std_srcdir}/limits \
>> 	${std_srcdir}/list \
>> 	${std_srcdir}/locale \
>>@@ -69,6 +70,7 @@ std_headers = \
>> 	${std_srcdir}/ratio \
>> 	${std_srcdir}/regex \
>> 	${std_srcdir}/scoped_allocator \
>>+	${std_srcdir}/semaphore \
>> 	${std_srcdir}/set \
>> 	${std_srcdir}/shared_mutex \
>> 	${std_srcdir}/span \
>>@@ -101,6 +103,8 @@ bits_headers = \
>> 	${bits_srcdir}/allocated_ptr.h \
>> 	${bits_srcdir}/allocator.h \
>> 	${bits_srcdir}/atomic_base.h \
>>+	${bits_srcdir}/atomic_wait.h \
>>+	${bits_srcdir}/atomic_timed_wait.h \
>> 	${bits_srcdir}/atomic_futex.h \
>> 	${bits_srcdir}/basic_ios.h \
>> 	${bits_srcdir}/basic_ios.tcc \
>>@@ -175,6 +179,7 @@ bits_headers = \
>> 	${bits_srcdir}/regex_compiler.tcc \
>> 	${bits_srcdir}/regex_executor.h \
>> 	${bits_srcdir}/regex_executor.tcc \
>>+	${bits_srcdir}/semaphore_base.h \
>> 	${bits_srcdir}/shared_ptr.h \
>> 	${bits_srcdir}/shared_ptr_atomic.h \
>> 	${bits_srcdir}/shared_ptr_base.h \
>>diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
>>index 2cdd2bd6cae..dd4db926592 100644
>>--- a/libstdc++-v3/include/bits/atomic_base.h
>>+++ b/libstdc++-v3/include/bits/atomic_base.h
>>@@ -37,6 +37,10 @@
>> #include <bits/atomic_lockfree_defines.h>
>> #include <bits/move.h>
>>
>>+#if __cplusplus > 201703L
>>+#include <bits/atomic_wait.h>
>>+#endif
>>+
>> #ifndef _GLIBCXX_ALWAYS_INLINE
>> #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
>> #endif
>>@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       return __ret;
>>     }
>>
>>-
>>   // Base types for atomics.
>>   template<typename _IntTp>
>>     struct __atomic_base;
>>@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       __atomic_load(&_M_i, &__v, int(__m));
>>       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
>>     }
>>+
>>+    _GLIBCXX_ALWAYS_INLINE void
>>+    wait(bool __old,
>>+	memory_order __m = memory_order_seq_cst) const noexcept
>>+    {
>>+      std::__atomic_wait(&_M_i, __old,
>>+			 [__m, this, __old]()
>>+			 { return this->test(__m) != __old; });
>>+    }
>>+
>>+    // TODO add const volatile overload
>>+
>>+    _GLIBCXX_ALWAYS_INLINE void
>>+    notify_one() const noexcept
>>+    { std::__atomic_notify(&_M_i, false); }
>>+
>>+    // TODO add const volatile overload
>>+
>>+    _GLIBCXX_ALWAYS_INLINE void
>>+    notify_all() const noexcept
>>+    { std::__atomic_notify(&_M_i, true); }
>>+
>>+    // TODO add const volatile overload
>> #endif // C++20
>>
>>     _GLIBCXX_ALWAYS_INLINE void
>>@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 				       __cmpexch_failure_order(__m));
>>       }
>>
>>+#if __cplusplus > 201703L
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(__int_type __old,
>>+	  memory_order __m = memory_order_seq_cst) const noexcept
>>+      {
>>+	std::__atomic_wait(&_M_i, __old,
>>+			   [__m, this, __old]
>>+			   { return this->load(__m) != __old; });
>>+      }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { std::__atomic_notify(&_M_i, false); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { std::__atomic_notify(&_M_i, true); }
>>+
>>+      // TODO add const volatile overload
>>+#endif // C++2a
>>+
>>       _GLIBCXX_ALWAYS_INLINE __int_type
>>       fetch_add(__int_type __i,
>> 		memory_order __m = memory_order_seq_cst) noexcept
>>@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 					   int(__m1), int(__m2));
>>       }
>>
>>+#if __cplusplus > 201703L
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(__pointer_type __old,
>>+	   memory_order __m = memory_order_seq_cst) noexcept
>>+      {
>>+	std::__atomic_wait(&_M_p, __old,
>>+		      [__m, this, __old]()
>>+		      { return this->load(__m) != __old; });
>>+      }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { std::__atomic_notify(&_M_p, false); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { std::__atomic_notify(&_M_p, true); }
>>+
>>+      // TODO add const volatile overload
>>+#endif // C++2a
>>+
>>       _GLIBCXX_ALWAYS_INLINE __pointer_type
>>       fetch_add(ptrdiff_t __d,
>> 		memory_order __m = memory_order_seq_cst) noexcept
>>@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 					 int(__success), int(__failure));
>>       }
>>
>>+#if __cplusplus > 201703L
>>+    template<typename _Tp>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(const _Tp* __ptr, _Val<_Tp> __old,
>>+	   memory_order __m = memory_order_seq_cst) noexcept
>>+      {
>>+	std::__atomic_wait(__ptr, __old,
>>+	    [=]() { return load(__ptr, __m) == __old; });
>>+      }
>>+
>>+      // TODO add const volatile overload
>>+
>>+    template<typename _Tp>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one(const _Tp* __ptr) noexcept
>>+      { std::__atomic_notify(__ptr, false); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+    template<typename _Tp>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all(const _Tp* __ptr) noexcept
>>+      { std::__atomic_notify(__ptr, true); }
>>+
>>+      // TODO add const volatile overload
>>+#endif // C++2a
>>+
>>     template<typename _Tp>
>>       _GLIBCXX_ALWAYS_INLINE _Tp
>>       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
>>@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 				       __cmpexch_failure_order(__order));
>>       }
>>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+      { __atomic_impl::wait(&_M_fp, __old, __m); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { __atomic_impl::notify_one(&_M_fp); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { __atomic_impl::notify_all(&_M_fp); }
>>+
>>+      // TODO add const volatile overload
>>+
>>       value_type
>>       fetch_add(value_type __i,
>> 		memory_order __m = memory_order_seq_cst) noexcept
>>@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 				       __cmpexch_failure_order(__order));
>>       }
>>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>     private:
>>       _Tp* _M_ptr;
>>     };
>>@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 				       __cmpexch_failure_order(__order));
>>       }
>>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>       value_type
>>       fetch_add(value_type __i,
>> 		memory_order __m = memory_order_seq_cst) const noexcept
>>@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 				       __cmpexch_failure_order(__order));
>>       }
>>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>       value_type
>>       fetch_add(value_type __i,
>> 		memory_order __m = memory_order_seq_cst) const noexcept
>>@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 				       __cmpexch_failure_order(__order));
>>       }
>>
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
>>+      { __atomic_impl::wait(_M_ptr, __old, __m); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_one() const noexcept
>>+      { __atomic_impl::notify_one(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>+      _GLIBCXX_ALWAYS_INLINE void
>>+      notify_all() const noexcept
>>+      { __atomic_impl::notify_all(_M_ptr); }
>>+
>>+      // TODO add const volatile overload
>>+
>>       _GLIBCXX_ALWAYS_INLINE value_type
>>       fetch_add(difference_type __d,
>> 		memory_order __m = memory_order_seq_cst) const noexcept
>>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>new file mode 100644
>>index 00000000000..2f57356b366
>>--- /dev/null
>>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
>>@@ -0,0 +1,281 @@
>>+// -*- C++ -*- header.
>>+
>>+// Copyright (C) 2020 Free Software Foundation, Inc.
>>+//
>>+// This file is part of the GNU ISO C++ Library.  This library is free
>>+// software; you can redistribute it and/or modify it under the
>>+// terms of the GNU General Public License as published by the
>>+// Free Software Foundation; either version 3, or (at your option)
>>+// any later version.
>>+
>>+// This library is distributed in the hope that it will be useful,
>>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>+// GNU General Public License for more details.
>>+
>>+// Under Section 7 of GPL version 3, you are granted additional
>>+// permissions described in the GCC Runtime Library Exception, version
>>+// 3.1, as published by the Free Software Foundation.
>>+
>>+// You should have received a copy of the GNU General Public License and
>>+// a copy of the GCC Runtime Library Exception along with this program;
>>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>>+// <http://www.gnu.org/licenses/>.
>>+
>>+/** @file bits/atomic_timed_wait.h
>>+ *  This is an internal header file, included by other library headers.
>>+ *  Do not attempt to use it directly. @headername{atomic}
>>+ */
>>+
>>+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
>>+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
>>+
>>+#pragma GCC system_header
>>+
>>+#include <bits/c++config.h>
>>+#include <bits/functional_hash.h>
>>+#include <bits/atomic_wait.h>
>>+
>>+#include <chrono>
>>+
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+#include <sys/time.h>
>>+#endif
>>+
>>+namespace std _GLIBCXX_VISIBILITY(default)
>>+{
>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>>+
>>+  enum class __atomic_wait_status { no_timeout, timeout };
>>+
>>+  namespace __detail
>>+  {
>>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>>+    using __platform_wait_clock_t = chrono::steady_clock;
>>+
>>+    template<typename _Duration>
>>+      __atomic_wait_status
>>+      __platform_wait_until_impl(__platform_wait_t* __addr,
>>+				 __platform_wait_t __val,
>>+				 const chrono::time_point<__platform_wait_clock_t,
>>+							  _Duration>& __atime) noexcept
>>+      {
>>+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>>+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>>+
>>+	struct timespec __rt =
>>+	{
>>+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>>+	  static_cast<long>(__ns.count())
>>+	};
>>+
>>+	auto __e = syscall (SYS_futex, __addr,
>>+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>>+			      __val, &__rt, nullptr,
>>+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
>>+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>>+	    std::terminate();
>>+	return (__platform_wait_clock_t::now() < __atime)
>>+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>>+      }
>>+
>>+    template<typename _Clock, typename _Duration>
>>+      __atomic_wait_status
>>+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>>+			    const chrono::time_point<_Clock, _Duration>& __atime)
>>+      {
>>+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
>
> This case is impossible, since the other overload would be selected
> if the clock is the __platform_wait_clock_t (unless the caller says
> __platform_wait_until<__platform_wait_until> to explicitly call this
> overload, but users can't call this function, and we won't do that).
>

Which overload?

>>+	  {
>>+	    return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
>>+	  }


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-28 21:29                     ` Thomas Rodgers
@ 2020-09-29  9:44                       ` Jonathan Wakely
  0 siblings, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-09-29  9:44 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: Thomas Rodgers, gcc-patches, libstdc++

On 28/09/20 14:29 -0700, Thomas Rodgers wrote:
>>>+    template<typename _Duration>
>>>+      __atomic_wait_status
>>>+      __platform_wait_until_impl(__platform_wait_t* __addr,
>>>+				 __platform_wait_t __val,
>>>+				 const chrono::time_point<__platform_wait_clock_t,
>>>+							  _Duration>& __atime) noexcept
>>>+      {
>>>+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>>>+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>>>+
>>>+	struct timespec __rt =
>>>+	{
>>>+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
>>>+	  static_cast<long>(__ns.count())
>>>+	};
>>>+
>>>+	auto __e = syscall (SYS_futex, __addr,
>>>+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
>>>+			      __val, &__rt, nullptr,
>>>+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
>>>+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
>>>+	    std::terminate();
>>>+	return (__platform_wait_clock_t::now() < __atime)
>>>+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
>>>+      }
>>>+
>>>+    template<typename _Clock, typename _Duration>
>>>+      __atomic_wait_status
>>>+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
>>>+			    const chrono::time_point<_Clock, _Duration>& __atime)
>>>+      {
>>>+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
>>
>> This case is impossible, since the other overload would be selected
>> if the clock is the __platform_wait_clock_t (unless the caller says
>> __platform_wait_until<__platform_wait_until> to explicitly call this
>> overload, but users can't call this function, and we won't do that).
>>
>
>Which overload?


I must have misread __platform_wait_until_impl above as
__platform_wait_until. Ignore this comment, sorry!



^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] libstdc++: Add C++2a synchronization support
  2020-09-28 13:25                   ` Jonathan Wakely
@ 2020-10-01 23:37                     ` Thomas Rodgers
  2020-10-02 15:40                       ` Thomas Rodgers
  2020-10-05 22:54                       ` [PATCH] t/trodgers/c2a_synchronization Thomas Rodgers
  0 siblings, 2 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-10-01 23:37 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers

From: Thomas Rodgers <trodgers@redhat.com>

Updated patch incorporating latest feedback.

Add support for -
  * atomic_flag::wait/notify_one/notify_all
  * atomic::wait/notify_one/notify_all
  * counting_semaphore
  * binary_semaphore
  * latch

libstdc++-v3/ChangeLog:

	* include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
	(__atomic_flag::notify_one): Likewise.
	(__atomic_flag::notify_all): Likewise.
	(__atomic_base<_Itp>::wait): Likewise.
	(__atomic_base<_Itp>::notify_one): Likewise.
	(__atomic_base<_Itp>::notify_all): Likewise.
	(__atomic_base<_Ptp*>::wait): Likewise.
	(__atomic_base<_Ptp*>::notify_one): Likewise.
	(__atomic_base<_Ptp*>::notify_all): Likewise.
	(__atomic_impl::wait): Likewise.
	(__atomic_impl::notify_one): Likewise.
	(__atomic_impl::notify_all): Likewise.
	(__atomic_float<_Fp>::wait): Likewise.
	(__atomic_float<_Fp>::notify_one): Likewise.
	(__atomic_float<_Fp>::notify_all): Likewise.
	(__atomic_ref<_Tp>::wait): Likewise.
	(__atomic_ref<_Tp>::notify_one): Likewise.
	(__atomic_ref<_Tp>::notify_all): Likewise.
	(atomic_wait<_Tp>): Likewise.
	(atomic_wait_explicit<_Tp>): Likewise.
	(atomic_notify_one<_Tp>): Likewise.
	(atomic_notify_all<_Tp>): Likewise.
	* include/bits/atomic_wait.h: New file.
	* include/bits/atomic_timed_wait.h: New file.
	* include/bits/semaphore_base.h: New file.
	* include/std/atomic (atomic<bool>::wait): Define.
	(atomic<bool>::wait_one): Likewise.
	(atomic<bool>::wait_all): Likewise.
	(atomic<_Tp>::wait): Likewise.
	(atomic<_Tp>::wait_one): Likewise.
	(atomic<_Tp>::wait_all): Likewise.
	(atomic<_Tp*>::wait): Likewise.
	(atomic<_Tp*>::wait_one): Likewise.
	(atomic<_Tp*>::wait_all): Likewise.
	* include/std/latch: New file.
	* include/std/semaphore: New file.
	* include/std/version: Add __cpp_lib_semaphore and
	__cpp_lib_latch defines.
	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
	* testsuite/30_thread/semaphore/1.cc: New test.
	* testsuite/30_thread/semaphore/2.cc: Likewise.
	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
	* testsuite/30_thread/latch/1.cc: New test.
	* testsuite/30_thread/latch/2.cc: New test.
	* testsuite/30_thread/latch/3.cc: New test.
---
 libstdc++-v3/include/Makefile.am              |   5 +
 libstdc++-v3/include/Makefile.in              |   5 +
 libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  73 +++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  92 ++++++
 libstdc++-v3/include/std/version              |   2 +
 .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
 .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
 .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
 .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
 .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
 .../atomic/wait_notify/integrals.cc           |  65 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
 libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
 .../testsuite/30_threads/semaphore/1.cc       |  27 ++
 .../testsuite/30_threads/semaphore/2.cc       |  27 ++
 .../semaphore/least_max_value_neg.cc          |  30 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 28 files changed, 2471 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
 create mode 100644 libstdc++-v3/include/std/latch
 create mode 100644 libstdc++-v3/include/std/semaphore
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch \
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
 	${std_srcdir}/scoped_allocator \
+	${std_srcdir}/semaphore \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
 	${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
+	${bits_srcdir}/atomic_timed_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
 	${bits_srcdir}/regex_compiler.tcc \
 	${bits_srcdir}/regex_executor.h \
 	${bits_srcdir}/regex_executor.tcc \
+	${bits_srcdir}/semaphore_base.h \
 	${bits_srcdir}/shared_ptr.h \
 	${bits_srcdir}/shared_ptr_atomic.h \
 	${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __atomic_load(&_M_i, &__v, int(__m));
       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
     }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait(bool __old,
+	memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]()
+			 { return this->test(__m) != __old; });
+    }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+
+    // TODO add const volatile overload
 #endif // C++20
 
     _GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__int_type __old,
+	  memory_order __m = memory_order_seq_cst) const noexcept
+      {
+	std::__atomic_wait(&_M_i, __old,
+			   [__m, this, __old]
+			   { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_i, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_i, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __int_type
       fetch_add(__int_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					   int(__m1), int(__m2));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__pointer_type __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(&_M_p, __old,
+		      [__m, this, __old]()
+		      { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_p, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_p, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					 int(__success), int(__failure));
       }
 
+#if __cplusplus > 201703L
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(const _Tp* __ptr, _Val<_Tp> __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(__ptr, __old,
+	    [=]() { return load(__ptr, __m) == __old; });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, false); }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
     template<typename _Tp>
       _GLIBCXX_ALWAYS_INLINE _Tp
       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(&_M_fp); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(&_M_fp); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
     private:
       _Tp* _M_ptr;
     };
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       _GLIBCXX_ALWAYS_INLINE value_type
       fetch_add(difference_type __d,
 		memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class __atomic_wait_status { no_timeout, timeout };
+
+  namespace __detail
+  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    using __platform_wait_clock_t = chrono::steady_clock;
+
+    template<typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until_impl(__platform_wait_t* __addr,
+				 __platform_wait_t __val,
+				 const chrono::time_point<__platform_wait_clock_t,
+							  _Duration>& __atime) noexcept
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	struct timespec __rt =
+	{
+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
+	  static_cast<long>(__ns.count())
+	};
+
+	auto __e = syscall (SYS_futex, __addr,
+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+			      __val, &__rt, nullptr,
+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+	    std::terminate();
+	return (__platform_wait_clock_t::now() < __atime)
+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+      }
+
+    template<typename _Clock, typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+			    const chrono::time_point<_Clock, _Duration>& __atime)
+      {
+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __platform_wait_clock_t::time_point __s_entry =
+		    __platform_wait_clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
+		    __atomic_wait_status::no_timeout)
+	      return __atomic_wait_status::no_timeout;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    if (_Clock::now() < __atime)
+	      return __atomic_wait_status::no_timeout;
+	    return __atomic_wait_status::timeout;
+	  }
+      }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Duration>
+      __atomic_wait_status
+      __cond_wait_until_impl(__gthread_cond_t* __cv,
+	  unique_lock<mutex>& __lock,
+	  const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	__gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+			       CLOCK_MONOTONIC,
+			       &__ts);
+	return (chrono::steady_clock::now() < __atime)
+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+      }
+#endif
+
+      template<typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until_impl(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+	{
+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	  __gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	  __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+				   &__ts);
+	  return (chrono::system_clock::now() < __atime)
+		 ? __atomic_wait_status::no_timeout
+		 : __atomic_wait_status::timeout;
+	}
+
+      // return true if timeout
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+	  using __clock_t = chrono::steady_clock;
+#else
+	  using __clock_t = chrono::system_clock;
+#endif
+	  const typename _Clock::time_point __c_entry = _Clock::now();
+	  const __clock_t::time_point __s_entry = __clock_t::now();
+	  const auto __delta = __atime - __c_entry;
+	  const auto __s_atime = __s_entry + __delta;
+	  if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+	    return __atomic_wait_status::no_timeout;
+	  // We got a timeout when measured against __clock_t but
+	  // we need to check against the caller-supplied clock
+	  // to tell whether we should return a timeout.
+	  if (_Clock::now() < __atime)
+	    return __atomic_wait_status::no_timeout;
+	  return __atomic_wait_status::timeout;
+	}
+
+    struct __timed_waiters : __waiters
+    {
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	_M_do_wait_until(__platform_wait_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	  return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+	  __platform_wait_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
+		    __atomic_wait_status::timeout)
+		return __atomic_wait_status::timeout;
+
+	      __platform_wait_t __last = __cur;
+	      __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	      if (__cur < __last)
+		break; // break the loop if version overflows
+	    }
+	  return __atomic_wait_status::no_timeout;
+#endif
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+      }
+    };
+  } // namespace __detail
+
+  template<typename _Tp, typename _Pred,
+	   typename _Clock, typename _Duration>
+    bool
+    __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+			const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+      auto __version = __w._M_enter_wait();
+      do
+	{
+	  __atomic_wait_status __res;
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+					    __old,
+					    __atime);
+	    }
+	  else
+	    {
+	      __res = __w._M_do_wait_until(__version, __atime);
+	    }
+	  if (__res == __atomic_wait_status::timeout)
+	    return false;
+	}
+      while (!__pred() && __atime < _Clock::now());
+      __w._M_leave_wait();
+
+      // if timed out, return false
+      return (_Clock::now() < __atime);
+    }
+
+  template<typename _Tp, typename _Pred,
+	   typename _Rep, typename _Period>
+    bool
+    __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+		      const chrono::duration<_Rep, _Period>& __rtime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      if (!__rtime.count())
+	return false; // no rtime supplied, and spin did not acquire
+
+      using __dur = chrono::steady_clock::duration;
+      auto __reltime = chrono::duration_cast<__dur>(__rtime);
+      if (__reltime < __rtime)
+	++__reltime;
+
+
+      return __atomic_wait_until(__addr, __old, std::move(__pred),
+				 chrono::steady_clock::now() + __reltime);
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..21ec3d38c94
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,301 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    constexpr auto __atomic_spin_count_1 = 16;
+    constexpr auto __atomic_spin_count_2 = 12;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+    template<typename _Tp>
+      inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	= is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+	= false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum class __futex_wait_flags : int
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __private_flag = 128,
+#else
+      __private_flag = 0,
+#endif
+      __wait = 0,
+      __wake = 1,
+      __wait_bitset = 9,
+      __wake_bitset = 10,
+      __wait_private = __wait | __private_flag,
+      __wake_private = __wake | __private_flag,
+      __wait_bitset_private = __wait_bitset | __private_flag,
+      __wake_bitset_private = __wake_bitset | __private_flag,
+      __bitset_match_any = -1
+    };
+
+    template<typename _Tp>
+      void
+      __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+      {
+	 auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+			      static_cast<int>(__futex_wait_flags::__wait_private),
+				__val, nullptr);
+	 if (__e && !(errno == EINTR || errno == EAGAIN))
+	   std::terminate();
+      }
+
+      template<typename _Tp>
+      void
+      __platform_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	syscall (SYS_futex, static_cast<const void*>(__addr),
+		  static_cast<int>(__futex_wait_flags::__wake_private),
+		    __all ? INT_MAX : 1);
+      }
+#endif
+
+    struct __waiters
+    {
+      __platform_wait_t alignas(64) _M_ver = 0;
+      __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#  ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#  else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#  endif
+#endif
+
+      __platform_wait_t
+      _M_enter_wait() noexcept
+      {
+	__platform_wait_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(__platform_wait_t __version) noexcept
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_wait(&_M_ver, __version);
+#else
+	__platform_wait_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      std::terminate();
+	    __platform_wait_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+#endif
+      }
+
+      __platform_wait_t
+      _M_waiting() const noexcept
+	{
+	  __platform_wait_t __res;
+	  __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+	  return __res;
+	}
+
+      void
+      _M_notify(bool __all) noexcept
+      {
+	__atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_notify(&_M_ver, __all);
+#else
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+#endif
+      }
+
+      static __waiters&
+      _S_for(const void* __t)
+      {
+	const unsigned char __mask = 0xf;
+	static __waiters __w[__mask + 1];
+
+	auto __key = _Hash_impl::hash(__t) & __mask;
+	return __w[__key];
+      }
+    };
+
+    struct __waiter
+    {
+      __waiters& _M_w;
+      __platform_wait_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+	  , _M_version(_M_w._M_enter_wait())
+	{ }
+
+      ~__waiter()
+      { _M_w._M_leave_wait(); }
+
+      void _M_do_wait() noexcept
+      { _M_w._M_do_wait(_M_version); }
+    };
+
+    void
+    __thread_relax() noexcept
+    {
+#if defined __i386__ || defined __x86_64__
+      __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    void
+    __thread_yield() noexcept
+   {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+     __gthread_yield();
+#endif
+    }
+
+  } // namespace __detail
+
+  template<typename _Pred>
+    bool
+    __atomic_spin(_Pred __pred) noexcept
+    {
+      for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < __detail::__atomic_spin_count_2)
+	    __detail::__thread_relax();
+	  else
+	    __detail::__thread_yield();
+	}
+      return false;
+    }
+
+  template<typename _Tp, typename _Pred>
+    void
+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+    {
+      using namespace __detail;
+      if (__atomic_spin(__pred))
+	return;
+
+      __waiter __w(__addr);
+      while (!__pred())
+	{
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __platform_wait(__addr, __old);
+	    }
+	  else
+	    {
+	      // TODO support timed backoff when this can be moved into the lib
+	      __w._M_do_wait();
+	    }
+	}
+    }
+
+  template<typename _Tp>
+    void
+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
+    {
+      using namespace __detail;
+      auto& __w = __waiters::_S_for((void*)__addr);
+      if (!__w._M_waiting())
+	return;
+
+      if constexpr (__platform_wait_uses_type<_Tp>)
+	{
+	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	}
+      else
+	{
+	  __w._M_notify(__all);
+	}
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..ed127a7a953
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#include <iostream>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  struct __platform_semaphore
+  {
+    using __clock_t = chrono::system_clock;
+    static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+    explicit __platform_semaphore(ptrdiff_t __count) noexcept
+    {
+      sem_init(&_M_semaphore, 0, __count);
+    }
+
+    __platform_semaphore(const __platform_semaphore&) = delete;
+    __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+    ~__platform_semaphore()
+    { sem_destroy(&_M_semaphore); }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_acquire() noexcept
+    {
+      for (;;)
+	{
+	  auto __err = sem_wait(&_M_semaphore);
+	  if (__err && (errno == EINTR))
+	    continue;
+	  else if (__err)
+	    std::terminate();
+	  else
+	    break;
+	}
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_release(std::ptrdiff_t __update) noexcept
+    {
+      for(; __update != 0; --__update)
+	{
+	   auto __err = sem_post(&_M_semaphore);
+	   if (__err)
+	     std::terminate();
+	}
+    }
+
+    bool
+    _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
+    {
+
+      auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+      struct timespec __ts =
+      {
+	static_cast<std::time_t>(__s.time_since_epoch().count()),
+	static_cast<long>(__ns.count())
+      };
+
+      for (;;)
+	{
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == EINTR))
+	      continue;
+	  else if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err && (errno == EINVAL))
+	      return false; // caller supplied an invalid __atime
+	  else if (__err)
+	      std::terminate();
+	  else
+	    break;
+	}
+      return true;
+    }
+
+    template<typename _Clock, typename _Duration>
+      bool
+      _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+      {
+	if constexpr (std::is_same<__clock_t, _Clock>::value)
+	  {
+	    return _M_try_acquire_until_impl(__atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __clock_t __s_entry = __clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (_M_try_acquire_until_impl(__s_atime))
+	      return true;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    return (_Clock::now() < __atime);
+	  }
+      }
+
+    template<typename _Rep, typename _Period>
+      _GLIBCXX_ALWAYS_INLINE bool
+      _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+      { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+    private:
+      sem_t _M_semaphore;
+    };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	static_assert(std::is_integral_v<_Tp>);
+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+	explicit __atomic_semaphore(_Tp __count) noexcept
+	  : _M_a(__count)
+	{ }
+
+	__atomic_semaphore(const __atomic_semaphore&) = delete;
+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+	_GLIBCXX_ALWAYS_INLINE void
+	_M_acquire() noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_a,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return __atomic_impl::compare_exchange_strong(&this->_M_a,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	  __atomic_wait(&_M_a, __old, __pred);
+	}
+
+	bool
+	_M_try_acquire() noexcept
+	{
+	  auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+	  if (__old == 0)
+	    return false;
+
+	  return __atomic_spin([this, &__old]
+	    {
+	      return __atomic_impl::compare_exchange_weak(&this->_M_a,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    });
+	}
+
+	template<typename _Clock, typename _Duration>
+	  _GLIBCXX_ALWAYS_INLINE bool
+	  _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	  {
+	    auto const __pred = [this]
+	      {
+		auto __old = __atomic_impl::load(&this->_M_a,
+				memory_order::acquire);
+		if (__old == 0)
+		  return false;
+		return __atomic_impl::compare_exchange_strong(&this->_M_a,
+				__old, __old - 1,
+				memory_order::acquire,
+				memory_order::release);
+	      };
+
+	    auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	    return __atomic_wait_until(&_M_a, __old, __pred, __atime);
+	}
+
+      template<typename _Rep, typename _Period>
+	_GLIBCXX_ALWAYS_INLINE bool
+	_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_a,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return  __atomic_impl::compare_exchange_strong(&this->_M_a,
+			      __old, __old - 1,
+			      memory_order::acquire,
+			      memory_order::release);
+	    };
+
+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	  return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
+	}
+
+      _GLIBCXX_ALWAYS_INLINE void
+      _M_release(ptrdiff_t __update) noexcept
+      {
+	if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
+	  return;
+	if (__update > 1)
+	  __atomic_impl::notify_all(&_M_a);
+	else
+	  __atomic_impl::notify_one(&_M_a);
+      }
+
+    private:
+      alignas(__alignof__(_Tp)) _Tp _M_a;
+    };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+  // Use futex if available and didn't force use of POSIX
+  using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  using __fast_semaphore = __platform_semaphore;
+#else
+  using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+  using __semaphore_impl = conditional_t<
+		(__least_max_value > 1),
+		conditional_t<
+		    (__least_max_value <= __fast_semaphore::_S_max),
+		    __fast_semaphore,
+		    __atomic_semaphore<ptrdiff_t>>,
+		__fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..c15909d9ccb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     compare_exchange_strong(bool& __i1, bool __i2,
 		    memory_order __m = memory_order_seq_cst) volatile noexcept
     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+    { _M_base.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_base.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_base.notify_all(); }
+#endif
   };
 
 #if __cplusplus <= 201703L
@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     memory_order __m = memory_order_seq_cst) volatile noexcept
       { return compare_exchange_strong(__e, __i, __m,
                                        __cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]
+			 {
+			   const auto __v = this->load(__m);
+			   // TODO make this ignore padding bits when we can do that
+			   return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
+			 });
+    }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    void notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					    __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+    void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+    { _M_b.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_b.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_b.notify_all(); }
+#endif
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 						     memory_order_seq_cst);
     }
 
+
+#if __cplusplus > 201703L
+  template<typename _Tp>
+    inline void
+    atomic_wait(const atomic<_Tp>* __a,
+	        typename std::atomic<_Tp>::value_type __old) noexcept
+    { __a->wait(__old); }
+
+  template<typename _Tp>
+    inline void
+    atomic_wait_explicit(const atomic<_Tp>* __a,
+			 typename std::atomic<_Tp>::value_type __old,
+			 std::memory_order __m) noexcept
+    { __a->wait(__old, __m); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_one(atomic<_Tp>* __a) noexcept
+    { __a->notify_one(); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_all(atomic<_Tp>* __a) noexcept
+    { __a->notify_all(); }
+
+#endif // C++2a
+
   // Function templates for atomic_integral and atomic_pointer operations only.
   // Some operations (and, or, xor) are only available for atomic integrals,
   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..bd06db5aa7f
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,90 @@
+// <latch> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class latch
+  {
+  public:
+    static constexpr ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) noexcept
+      : _M_a(__expected) { }
+
+    ~latch() = default;
+    latch(const latch&) = delete;
+    latch& operator=(const latch&) = delete;
+
+    _GLIBCXX_ALWAYS_INLINE void
+    count_down(ptrdiff_t __update = 1)
+    {
+      auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
+      if (__old == __update)
+	__atomic_impl::notify_all(&_M_a);
+    }
+
+    _GLIBCXX_ALWAYS_INLINE bool
+    try_wait() const noexcept
+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait() const
+    {
+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+      __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    arrive_and_wait(ptrdiff_t __update = 1)
+    {
+      count_down();
+      wait();
+    }
+
+  private:
+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+  };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..865d6c4aecb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<ptrdiff_t __least_max_value =
+			__gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
+    class counting_semaphore
+    {
+      static_assert(__least_max_value >= 0);
+
+      __semaphore_impl<__least_max_value> _M_sem;
+
+    public:
+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
+	: _M_sem(__desired)
+      { }
+
+      ~counting_semaphore() = default;
+
+      counting_semaphore(const counting_semaphore&) = delete;
+      counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+      static constexpr ptrdiff_t
+      max() noexcept
+      { return __least_max_value; }
+
+      void
+      release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+      { _M_sem._M_release(__update); }
+
+      void
+      acquire() noexcept(noexcept(_M_sem._M_acquire()))
+      { _M_sem._M_acquire(); }
+
+      bool
+      try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+      { return _M_sem._M_try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool
+	try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+	{ return _M_sem._M_try_acquire_for(__rtime); }
+
+      template<class _Clock, class _Dur>
+	bool
+	try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+	{ return _M_sem._M_try_acquire_until(__atime); }
+    };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..b9c7c6c62a8 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,12 +216,14 @@
 #ifdef _GLIBCXX_HAS_GTHREADS
 # define __cpp_lib_jthread 201911L
 #endif
+#define __cpp_lib_latch 201907L
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
 #define __cpp_lib_polymorphic_allocator 201902L
 #if __cpp_lib_concepts
 # define __cpp_lib_ranges 201911L
 #endif
+#define __cpp_lib_semaphore 201907L
 #define __cpp_lib_shift 201806L
 #define __cpp_lib_span 202002L
 #define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  Tp aa = val1;
+  std::atomic_ref<Tp> a(aa);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp,
+	 bool = std::is_integral_v<Tp>
+	 || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+  check(Tp b)
+  {
+    Tp a;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+struct foo
+{
+  long a = 0;
+  long b = 0;
+
+  foo& operator=(foo const&) = default;
+
+  friend bool
+  operator==(foo const& rhs, foo const& lhs)
+  { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+  check<long>();
+  check<double>();
+  check<foo>({42, 48});
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..b9fc063c66f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<bool> a(false);
+  std::atomic<bool> b(false);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+		  if (a.load())
+                  {
+		    b.store(true);
+                  }
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(true);
+  a.notify_one();
+  t.join();
+  VERIFY( b.load() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
new file mode 100644
index 00000000000..1d032085752
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+int
+main ()
+{
+  check<float> f;
+  check<double> d;
+  check<long double> l;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..d15b9c86ae6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+int
+main ()
+{
+  struct S{ int i; };
+  check<S> check_s{S{0},S{42}};
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,160 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+  check(Tp a = 0, Tp b = 42)
+  {
+    if constexpr (std::equality_comparable<Tp>)
+    {
+      VERIFY( check_wait_notify(a, b) == b);
+      VERIFY( check_atomic_wait_notify(a, b) == b);
+    }
+    else
+    {
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+      }
+
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_atomic_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+      }
+    }
+  }
+};
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
new file mode 100644
index 00000000000..115cb79a040
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+void
+test01()
+{
+  struct S{ int i; };
+  std::atomic<S> s;
+
+  s.wait(S{42});
+}
+
+int
+main ()
+{
+  // check<bool> bb;
+  check<char> ch;
+  check<signed char> sch;
+  check<unsigned char> uch;
+  check<short> s;
+  check<unsigned short> us;
+  check<int> i;
+  check<unsigned int> ui;
+  check<long> l;
+  check<unsigned long> ul;
+  check<long long> ll;
+  check<unsigned long long> ull;
+
+  check<wchar_t> wch;
+  check<char8_t> ch8;
+  check<char16_t> ch16;
+  check<char32_t> ch32;
+
+  check<int8_t> i8;
+  check<int16_t> i16;
+  check<int32_t> i32;
+  check<int64_t> i64;
+
+  check<uint8_t> u8;
+  check<uint16_t> u16;
+  check<uint32_t> u32;
+  check<uint64_t> u64;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  long aa;
+  long bb;
+
+  std::atomic<long*> a(nullptr);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(nullptr);
+		  if (a.load() == &aa)
+		    a.store(&bb);
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(&aa);
+  a.notify_one();
+  t.join();
+  VERIFY( a.load() == &bb);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..6de7873ecc2
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic_flag a;
+  std::atomic_flag b;
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+                  b.test_and_set();
+                  b.notify_one();
+		});
+
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.test_and_set();
+  a.notify_one();
+  b.wait(false);
+  t.join();
+
+  VERIFY( a.test() );
+  VERIFY( b.test() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::atomic<int> a(0);
+
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    ++a;
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2



^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] libstdc++: Add C++2a synchronization support
  2020-10-01 23:37                     ` Thomas Rodgers
@ 2020-10-02 15:40                       ` Thomas Rodgers
  2020-10-05 22:54                       ` [PATCH] t/trodgers/c2a_synchronization Thomas Rodgers
  1 sibling, 0 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-10-02 15:40 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers

From: Thomas Rodgers <trodgers@redhat.com>

Updated patch incorporating latest feedback (revised).

Add support for -
  * atomic_flag::wait/notify_one/notify_all
  * atomic::wait/notify_one/notify_all
  * counting_semaphore
  * binary_semaphore
  * latch

libstdc++-v3/ChangeLog:

	* include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
	(__atomic_flag::notify_one): Likewise.
	(__atomic_flag::notify_all): Likewise.
	(__atomic_base<_Itp>::wait): Likewise.
	(__atomic_base<_Itp>::notify_one): Likewise.
	(__atomic_base<_Itp>::notify_all): Likewise.
	(__atomic_base<_Ptp*>::wait): Likewise.
	(__atomic_base<_Ptp*>::notify_one): Likewise.
	(__atomic_base<_Ptp*>::notify_all): Likewise.
	(__atomic_impl::wait): Likewise.
	(__atomic_impl::notify_one): Likewise.
	(__atomic_impl::notify_all): Likewise.
	(__atomic_float<_Fp>::wait): Likewise.
	(__atomic_float<_Fp>::notify_one): Likewise.
	(__atomic_float<_Fp>::notify_all): Likewise.
	(__atomic_ref<_Tp>::wait): Likewise.
	(__atomic_ref<_Tp>::notify_one): Likewise.
	(__atomic_ref<_Tp>::notify_all): Likewise.
	(atomic_wait<_Tp>): Likewise.
	(atomic_wait_explicit<_Tp>): Likewise.
	(atomic_notify_one<_Tp>): Likewise.
	(atomic_notify_all<_Tp>): Likewise.
	* include/bits/atomic_wait.h: New file.
	* include/bits/atomic_timed_wait.h: New file.
	* include/bits/semaphore_base.h: New file.
	* include/std/atomic (atomic<bool>::wait): Define.
	(atomic<bool>::wait_one): Likewise.
	(atomic<bool>::wait_all): Likewise.
	(atomic<_Tp>::wait): Likewise.
	(atomic<_Tp>::wait_one): Likewise.
	(atomic<_Tp>::wait_all): Likewise.
	(atomic<_Tp*>::wait): Likewise.
	(atomic<_Tp*>::wait_one): Likewise.
	(atomic<_Tp*>::wait_all): Likewise.
	* include/std/latch: New file.
	* include/std/semaphore: New file.
	* include/std/version: Add __cpp_lib_semaphore and
	__cpp_lib_latch defines.
	* testsuite/29_atomic/atomic/wait_notify/atomic_refs.cc: New test.
	* testsuite/29_atomic/atomic/wait_notify/bool.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/integrals.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/floats.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
	* testsuite/29_atomic/atomic/wait_notify/generic.h: New File.
	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: New test.
	* testsuite/30_thread/semaphore/1.cc: New test.
	* testsuite/30_thread/semaphore/2.cc: Likewise.
	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
	* testsuite/30_thread/latch/1.cc: New test.
	* testsuite/30_thread/latch/2.cc: New test.
	* testsuite/30_thread/latch/3.cc: New test.
---
 libstdc++-v3/include/Makefile.am              |   5 +
 libstdc++-v3/include/Makefile.in              |   5 +
 libstdc++-v3/include/bits/atomic_base.h       | 195 +++++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 281 ++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 301 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 283 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  73 +++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  92 ++++++
 libstdc++-v3/include/std/version              |   2 +
 .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
 .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
 .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
 .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
 .../29_atomics/atomic/wait_notify/generic.h   | 160 ++++++++++
 .../atomic/wait_notify/integrals.cc           |  65 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
 libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/3.cc  |  50 +++
 .../testsuite/30_threads/semaphore/1.cc       |  27 ++
 .../testsuite/30_threads/semaphore/2.cc       |  27 ++
 .../semaphore/least_max_value_neg.cc          |  30 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 28 files changed, 2471 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
 create mode 100644 libstdc++-v3/include/std/latch
 create mode 100644 libstdc++-v3/include/std/semaphore
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch \
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
 	${std_srcdir}/scoped_allocator \
+	${std_srcdir}/semaphore \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
 	${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
+	${bits_srcdir}/atomic_timed_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
 	${bits_srcdir}/regex_compiler.tcc \
 	${bits_srcdir}/regex_executor.h \
 	${bits_srcdir}/regex_executor.tcc \
+	${bits_srcdir}/semaphore_base.h \
 	${bits_srcdir}/shared_ptr.h \
 	${bits_srcdir}/shared_ptr_atomic.h \
 	${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __atomic_load(&_M_i, &__v, int(__m));
       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
     }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait(bool __old,
+	memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]()
+			 { return this->test(__m) != __old; });
+    }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+
+    // TODO add const volatile overload
 #endif // C++20
 
     _GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__int_type __old,
+	  memory_order __m = memory_order_seq_cst) const noexcept
+      {
+	std::__atomic_wait(&_M_i, __old,
+			   [__m, this, __old]
+			   { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_i, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_i, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __int_type
       fetch_add(__int_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					   int(__m1), int(__m2));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__pointer_type __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(&_M_p, __old,
+		      [__m, this, __old]()
+		      { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_p, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_p, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					 int(__success), int(__failure));
       }
 
+#if __cplusplus > 201703L
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(const _Tp* __ptr, _Val<_Tp> __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(__ptr, __old,
+	    [=]() { return load(__ptr, __m) == __old; });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, false); }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
     template<typename _Tp>
       _GLIBCXX_ALWAYS_INLINE _Tp
       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(&_M_fp); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(&_M_fp); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
     private:
       _Tp* _M_ptr;
     };
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       _GLIBCXX_ALWAYS_INLINE value_type
       fetch_add(difference_type __d,
 		memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class __atomic_wait_status { no_timeout, timeout };
+
+  namespace __detail
+  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    using __platform_wait_clock_t = chrono::steady_clock;
+
+    template<typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until_impl(__platform_wait_t* __addr,
+				 __platform_wait_t __val,
+				 const chrono::time_point<__platform_wait_clock_t,
+							  _Duration>& __atime) noexcept
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	struct timespec __rt =
+	{
+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
+	  static_cast<long>(__ns.count())
+	};
+
+	auto __e = syscall (SYS_futex, __addr,
+			      static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+			      __val, &__rt, nullptr,
+			      static_cast<int>(__futex_wait_flags::__bitset_match_any));
+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+	    std::terminate();
+	return (__platform_wait_clock_t::now() < __atime)
+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+      }
+
+    template<typename _Clock, typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+			    const chrono::time_point<_Clock, _Duration>& __atime)
+      {
+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return std::__detail::__platform_wait_until_impl(__addr, __val, __atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __platform_wait_clock_t::time_point __s_entry =
+		    __platform_wait_clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (std::__detail::__platform_wait_until_impl(__addr, __val, __s_atime) ==
+		    __atomic_wait_status::no_timeout)
+	      return __atomic_wait_status::no_timeout;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    if (_Clock::now() < __atime)
+	      return __atomic_wait_status::no_timeout;
+	    return __atomic_wait_status::timeout;
+	  }
+      }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Duration>
+      __atomic_wait_status
+      __cond_wait_until_impl(__gthread_cond_t* __cv,
+	  unique_lock<mutex>& __lock,
+	  const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	__gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+			       CLOCK_MONOTONIC,
+			       &__ts);
+	return (chrono::steady_clock::now() < __atime)
+	       ? __atomic_wait_status::no_timeout : __atomic_wait_status::timeout;
+      }
+#endif
+
+      template<typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until_impl(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+	{
+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	  __gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	  __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+				   &__ts);
+	  return (chrono::system_clock::now() < __atime)
+		 ? __atomic_wait_status::no_timeout
+		 : __atomic_wait_status::timeout;
+	}
+
+      // return true if timeout
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+	  using __clock_t = chrono::steady_clock;
+#else
+	  using __clock_t = chrono::system_clock;
+#endif
+	  const typename _Clock::time_point __c_entry = _Clock::now();
+	  const __clock_t::time_point __s_entry = __clock_t::now();
+	  const auto __delta = __atime - __c_entry;
+	  const auto __s_atime = __s_entry + __delta;
+	  if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+	    return __atomic_wait_status::no_timeout;
+	  // We got a timeout when measured against __clock_t but
+	  // we need to check against the caller-supplied clock
+	  // to tell whether we should return a timeout.
+	  if (_Clock::now() < __atime)
+	    return __atomic_wait_status::no_timeout;
+	  return __atomic_wait_status::timeout;
+	}
+
+    struct __timed_waiters : __waiters
+    {
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	_M_do_wait_until(__platform_wait_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	  return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+	  __platform_wait_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (std::__detail::__cond_wait_until(&_M_cv, __l, __atime) ==
+		    __atomic_wait_status::timeout)
+		return __atomic_wait_status::timeout;
+
+	      __platform_wait_t __last = __cur;
+	      __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	      if (__cur < __last)
+		break; // break the loop if version overflows
+	    }
+	  return __atomic_wait_status::no_timeout;
+#endif
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+      }
+    };
+  } // namespace __detail
+
+  template<typename _Tp, typename _Pred,
+	   typename _Clock, typename _Duration>
+    bool
+    __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+			const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+      auto __version = __w._M_enter_wait();
+      do
+	{
+	  __atomic_wait_status __res;
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+					    __old,
+					    __atime);
+	    }
+	  else
+	    {
+	      __res = __w._M_do_wait_until(__version, __atime);
+	    }
+	  if (__res == __atomic_wait_status::timeout)
+	    return false;
+	}
+      while (!__pred() && __atime < _Clock::now());
+      __w._M_leave_wait();
+
+      // if timed out, return false
+      return (_Clock::now() < __atime);
+    }
+
+  template<typename _Tp, typename _Pred,
+	   typename _Rep, typename _Period>
+    bool
+    __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+		      const chrono::duration<_Rep, _Period>& __rtime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      if (!__rtime.count())
+	return false; // no rtime supplied, and spin did not acquire
+
+      using __dur = chrono::steady_clock::duration;
+      auto __reltime = chrono::duration_cast<__dur>(__rtime);
+      if (__reltime < __rtime)
+	++__reltime;
+
+
+      return __atomic_wait_until(__addr, __old, std::move(__pred),
+				 chrono::steady_clock::now() + __reltime);
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..21ec3d38c94
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,301 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    constexpr auto __atomic_spin_count_1 = 16;
+    constexpr auto __atomic_spin_count_2 = 12;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+    template<typename _Tp>
+      inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	= is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+	= false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum class __futex_wait_flags : int
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __private_flag = 128,
+#else
+      __private_flag = 0,
+#endif
+      __wait = 0,
+      __wake = 1,
+      __wait_bitset = 9,
+      __wake_bitset = 10,
+      __wait_private = __wait | __private_flag,
+      __wake_private = __wake | __private_flag,
+      __wait_bitset_private = __wait_bitset | __private_flag,
+      __wake_bitset_private = __wake_bitset | __private_flag,
+      __bitset_match_any = -1
+    };
+
+    template<typename _Tp>
+      void
+      __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+      {
+	 auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+			      static_cast<int>(__futex_wait_flags::__wait_private),
+				__val, nullptr);
+	 if (__e && !(errno == EINTR || errno == EAGAIN))
+	   std::terminate();
+      }
+
+      template<typename _Tp>
+      void
+      __platform_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	syscall (SYS_futex, static_cast<const void*>(__addr),
+		  static_cast<int>(__futex_wait_flags::__wake_private),
+		    __all ? INT_MAX : 1);
+      }
+#endif
+
+    struct __waiters
+    {
+      __platform_wait_t alignas(64) _M_ver = 0;
+      __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#  ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#  else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#  endif
+#endif
+
+      __platform_wait_t
+      _M_enter_wait() noexcept
+      {
+	__platform_wait_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(__platform_wait_t __version) noexcept
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_wait(&_M_ver, __version);
+#else
+	__platform_wait_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      std::terminate();
+	    __platform_wait_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+#endif
+      }
+
+      __platform_wait_t
+      _M_waiting() const noexcept
+	{
+	  __platform_wait_t __res;
+	  __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+	  return __res;
+	}
+
+      void
+      _M_notify(bool __all) noexcept
+      {
+	__atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_notify(&_M_ver, __all);
+#else
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+#endif
+      }
+
+      static __waiters&
+      _S_for(const void* __t)
+      {
+	const unsigned char __mask = 0xf;
+	static __waiters __w[__mask + 1];
+
+	auto __key = _Hash_impl::hash(__t) & __mask;
+	return __w[__key];
+      }
+    };
+
+    struct __waiter
+    {
+      __waiters& _M_w;
+      __platform_wait_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+	  , _M_version(_M_w._M_enter_wait())
+	{ }
+
+      ~__waiter()
+      { _M_w._M_leave_wait(); }
+
+      void _M_do_wait() noexcept
+      { _M_w._M_do_wait(_M_version); }
+    };
+
+    void
+    __thread_relax() noexcept
+    {
+#if defined __i386__ || defined __x86_64__
+      __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    void
+    __thread_yield() noexcept
+   {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+     __gthread_yield();
+#endif
+    }
+
+  } // namespace __detail
+
+  template<typename _Pred>
+    bool
+    __atomic_spin(_Pred __pred) noexcept
+    {
+      for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < __detail::__atomic_spin_count_2)
+	    __detail::__thread_relax();
+	  else
+	    __detail::__thread_yield();
+	}
+      return false;
+    }
+
+  template<typename _Tp, typename _Pred>
+    void
+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+    {
+      using namespace __detail;
+      if (__atomic_spin(__pred))
+	return;
+
+      __waiter __w(__addr);
+      while (!__pred())
+	{
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __platform_wait(__addr, __old);
+	    }
+	  else
+	    {
+	      // TODO support timed backoff when this can be moved into the lib
+	      __w._M_do_wait();
+	    }
+	}
+    }
+
+  template<typename _Tp>
+    void
+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
+    {
+      using namespace __detail;
+      auto& __w = __waiters::_S_for((void*)__addr);
+      if (!__w._M_waiting())
+	return;
+
+      if constexpr (__platform_wait_uses_type<_Tp>)
+	{
+	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	}
+      else
+	{
+	  __w._M_notify(__all);
+	}
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..ed127a7a953
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#include <iostream>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  struct __platform_semaphore
+  {
+    using __clock_t = chrono::system_clock;
+    static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+    explicit __platform_semaphore(ptrdiff_t __count) noexcept
+    {
+      sem_init(&_M_semaphore, 0, __count);
+    }
+
+    __platform_semaphore(const __platform_semaphore&) = delete;
+    __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+    ~__platform_semaphore()
+    { sem_destroy(&_M_semaphore); }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_acquire() noexcept
+    {
+      for (;;)
+	{
+	  auto __err = sem_wait(&_M_semaphore);
+	  if (__err && (errno == EINTR))
+	    continue;
+	  else if (__err)
+	    std::terminate();
+	  else
+	    break;
+	}
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_release(std::ptrdiff_t __update) noexcept
+    {
+      for(; __update != 0; --__update)
+	{
+	   auto __err = sem_post(&_M_semaphore);
+	   if (__err)
+	     std::terminate();
+	}
+    }
+
+    bool
+    _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
+    {
+
+      auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+      struct timespec __ts =
+      {
+	static_cast<std::time_t>(__s.time_since_epoch().count()),
+	static_cast<long>(__ns.count())
+      };
+
+      for (;;)
+	{
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == EINTR))
+	      continue;
+	  else if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err && (errno == EINVAL))
+	      return false; // caller supplied an invalid __atime
+	  else if (__err)
+	      std::terminate();
+	  else
+	    break;
+	}
+      return true;
+    }
+
+    template<typename _Clock, typename _Duration>
+      bool
+      _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+      {
+	if constexpr (std::is_same<__clock_t, _Clock>::value)
+	  {
+	    return _M_try_acquire_until_impl(__atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __clock_t __s_entry = __clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (_M_try_acquire_until_impl(__s_atime))
+	      return true;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    return (_Clock::now() < __atime);
+	  }
+      }
+
+    template<typename _Rep, typename _Period>
+      _GLIBCXX_ALWAYS_INLINE bool
+      _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+      { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+    private:
+      sem_t _M_semaphore;
+    };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	static_assert(std::is_integral_v<_Tp>);
+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+	explicit __atomic_semaphore(_Tp __count) noexcept
+	  : _M_a(__count)
+	{ }
+
+	__atomic_semaphore(const __atomic_semaphore&) = delete;
+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+	_GLIBCXX_ALWAYS_INLINE void
+	_M_acquire() noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_a,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return __atomic_impl::compare_exchange_strong(&this->_M_a,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	  __atomic_wait(&_M_a, __old, __pred);
+	}
+
+	bool
+	_M_try_acquire() noexcept
+	{
+	  auto __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+	  if (__old == 0)
+	    return false;
+
+	  return __atomic_spin([this, &__old]
+	    {
+	      return __atomic_impl::compare_exchange_weak(&this->_M_a,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    });
+	}
+
+	template<typename _Clock, typename _Duration>
+	  _GLIBCXX_ALWAYS_INLINE bool
+	  _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	  {
+	    auto const __pred = [this]
+	      {
+		auto __old = __atomic_impl::load(&this->_M_a,
+				memory_order::acquire);
+		if (__old == 0)
+		  return false;
+		return __atomic_impl::compare_exchange_strong(&this->_M_a,
+				__old, __old - 1,
+				memory_order::acquire,
+				memory_order::release);
+	      };
+
+	    auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	    return __atomic_wait_until(&_M_a, __old, __pred, __atime);
+	}
+
+      template<typename _Rep, typename _Period>
+	_GLIBCXX_ALWAYS_INLINE bool
+	_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_a,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return  __atomic_impl::compare_exchange_strong(&this->_M_a,
+			      __old, __old - 1,
+			      memory_order::acquire,
+			      memory_order::release);
+	    };
+
+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
+	  return __atomic_wait_for(&_M_a, __old, __pred, __rtime);
+	}
+
+      _GLIBCXX_ALWAYS_INLINE void
+      _M_release(ptrdiff_t __update) noexcept
+      {
+	if (0 < __atomic_impl::fetch_add(&_M_a, __update, memory_order_release))
+	  return;
+	if (__update > 1)
+	  __atomic_impl::notify_all(&_M_a);
+	else
+	  __atomic_impl::notify_one(&_M_a);
+      }
+
+    private:
+      alignas(__alignof__(_Tp)) _Tp _M_a;
+    };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+  // Use futex if available and didn't force use of POSIX
+  using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  using __fast_semaphore = __platform_semaphore;
+#else
+  using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+  using __semaphore_impl = conditional_t<
+		(__least_max_value > 1),
+		conditional_t<
+		    (__least_max_value <= __fast_semaphore::_S_max),
+		    __fast_semaphore,
+		    __atomic_semaphore<ptrdiff_t>>,
+		__fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..c15909d9ccb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     compare_exchange_strong(bool& __i1, bool __i2,
 		    memory_order __m = memory_order_seq_cst) volatile noexcept
     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+    { _M_base.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_base.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_base.notify_all(); }
+#endif
   };
 
 #if __cplusplus <= 201703L
@@ -363,6 +376,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     memory_order __m = memory_order_seq_cst) volatile noexcept
       { return compare_exchange_strong(__e, __i, __m,
                                        __cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]
+			 {
+			   const auto __v = this->load(__m);
+			   // TODO make this ignore padding bits when we can do that
+			   return __builtin_memcmp(&__old, &__v, sizeof(_Tp)) != 0;
+			 });
+    }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    void notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -601,6 +635,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					    __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+    void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+    { _M_b.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_b.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_b.notify_all(); }
+#endif
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1399,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 						     memory_order_seq_cst);
     }
 
+
+#if __cplusplus > 201703L
+  template<typename _Tp>
+    inline void
+    atomic_wait(const atomic<_Tp>* __a,
+	        typename std::atomic<_Tp>::value_type __old) noexcept
+    { __a->wait(__old); }
+
+  template<typename _Tp>
+    inline void
+    atomic_wait_explicit(const atomic<_Tp>* __a,
+			 typename std::atomic<_Tp>::value_type __old,
+			 std::memory_order __m) noexcept
+    { __a->wait(__old, __m); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_one(atomic<_Tp>* __a) noexcept
+    { __a->notify_one(); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_all(atomic<_Tp>* __a) noexcept
+    { __a->notify_all(); }
+
+#endif // C++2a
+
   // Function templates for atomic_integral and atomic_pointer operations only.
   // Some operations (and, or, xor) are only available for atomic integrals,
   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..bd06db5aa7f
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,90 @@
+// <latch> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class latch
+  {
+  public:
+    static constexpr ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) noexcept
+      : _M_a(__expected) { }
+
+    ~latch() = default;
+    latch(const latch&) = delete;
+    latch& operator=(const latch&) = delete;
+
+    _GLIBCXX_ALWAYS_INLINE void
+    count_down(ptrdiff_t __update = 1)
+    {
+      auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, memory_order::release);
+      if (__old == __update)
+	__atomic_impl::notify_all(&_M_a);
+    }
+
+    _GLIBCXX_ALWAYS_INLINE bool
+    try_wait() const noexcept
+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait() const
+    {
+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+      __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    arrive_and_wait(ptrdiff_t __update = 1)
+    {
+      count_down();
+      wait();
+    }
+
+  private:
+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+  };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..865d6c4aecb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<ptrdiff_t __least_max_value =
+			__gnu_cxx::__numeric_traits<ptrdiff_t>::__max>
+    class counting_semaphore
+    {
+      static_assert(__least_max_value >= 0);
+
+      __semaphore_impl<__least_max_value> _M_sem;
+
+    public:
+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
+	: _M_sem(__desired)
+      { }
+
+      ~counting_semaphore() = default;
+
+      counting_semaphore(const counting_semaphore&) = delete;
+      counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+      static constexpr ptrdiff_t
+      max() noexcept
+      { return __least_max_value; }
+
+      void
+      release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+      { _M_sem._M_release(__update); }
+
+      void
+      acquire() noexcept(noexcept(_M_sem._M_acquire()))
+      { _M_sem._M_acquire(); }
+
+      bool
+      try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+      { return _M_sem._M_try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool
+	try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+	{ return _M_sem._M_try_acquire_for(__rtime); }
+
+      template<class _Clock, class _Dur>
+	bool
+	try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+	{ return _M_sem._M_try_acquire_until(__atime); }
+    };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d5d42ed0a72..b9c7c6c62a8 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,12 +216,14 @@
 #ifdef _GLIBCXX_HAS_GTHREADS
 # define __cpp_lib_jthread 201911L
 #endif
+#define __cpp_lib_latch 201907L
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
 #define __cpp_lib_polymorphic_allocator 201902L
 #if __cpp_lib_concepts
 # define __cpp_lib_ranges 201911L
 #endif
+#define __cpp_lib_semaphore 201907L
 #define __cpp_lib_shift 201806L
 #define __cpp_lib_span 202002L
 #define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  Tp aa = val1;
+  std::atomic_ref<Tp> a(aa);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp,
+	 bool = std::is_integral_v<Tp>
+	 || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+  check(Tp b)
+  {
+    Tp a;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+struct foo
+{
+  long a = 0;
+  long b = 0;
+
+  foo& operator=(foo const&) = default;
+
+  friend bool
+  operator==(foo const& rhs, foo const& lhs)
+  { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+  check<long>();
+  check<double>();
+  check<foo>({42, 48});
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..b9fc063c66f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<bool> a(false);
+  std::atomic<bool> b(false);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+		  if (a.load())
+                  {
+		    b.store(true);
+                  }
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(true);
+  a.notify_one();
+  t.join();
+  VERIFY( b.load() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
new file mode 100644
index 00000000000..1d032085752
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+int
+main ()
+{
+  check<float> f;
+  check<double> d;
+  check<long double> l;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..d15b9c86ae6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+int
+main ()
+{
+  struct S{ int i; };
+  check<S> check_s{S{0},S{42}};
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,160 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+  check(Tp a = 0, Tp b = 42)
+  {
+    if constexpr (std::equality_comparable<Tp>)
+    {
+      VERIFY( check_wait_notify(a, b) == b);
+      VERIFY( check_atomic_wait_notify(a, b) == b);
+    }
+    else
+    {
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+      }
+
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_atomic_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+      }
+    }
+  }
+};
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
new file mode 100644
index 00000000000..115cb79a040
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "generic.h"
+
+void
+test01()
+{
+  struct S{ int i; };
+  std::atomic<S> s;
+
+  s.wait(S{42});
+}
+
+int
+main ()
+{
+  // check<bool> bb;
+  check<char> ch;
+  check<signed char> sch;
+  check<unsigned char> uch;
+  check<short> s;
+  check<unsigned short> us;
+  check<int> i;
+  check<unsigned int> ui;
+  check<long> l;
+  check<unsigned long> ul;
+  check<long long> ll;
+  check<unsigned long long> ull;
+
+  check<wchar_t> wch;
+  check<char8_t> ch8;
+  check<char16_t> ch16;
+  check<char32_t> ch32;
+
+  check<int8_t> i8;
+  check<int16_t> i16;
+  check<int32_t> i32;
+  check<int64_t> i64;
+
+  check<uint8_t> u8;
+  check<uint16_t> u16;
+  check<uint32_t> u32;
+  check<uint64_t> u64;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  long aa;
+  long bb;
+
+  std::atomic<long*> a(nullptr);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(nullptr);
+		  if (a.load() == &aa)
+		    a.store(&bb);
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(&aa);
+  a.notify_one();
+  t.join();
+  VERIFY( a.load() == &bb);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..6de7873ecc2
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic_flag a;
+  std::atomic_flag b;
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+                  b.test_and_set();
+                  b.notify_one();
+		});
+
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.test_and_set();
+  a.notify_one();
+  b.wait(false);
+  t.join();
+
+  VERIFY( a.test() );
+  VERIFY( b.test() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..cf1a31f996b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::atomic<int> a(0);
+
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    ++a;
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2



^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] t/trodgers/c2a_synchronization
  2020-10-01 23:37                     ` Thomas Rodgers
  2020-10-02 15:40                       ` Thomas Rodgers
@ 2020-10-05 22:54                       ` Thomas Rodgers
  2020-10-23 10:28                         ` Jonathan Wakely
  1 sibling, 1 reply; 43+ messages in thread
From: Thomas Rodgers @ 2020-10-05 22:54 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers

From: Thomas Rodgers <trodgers@redhat.com>

This *should* be the correct patch this time.

Add support for -
  * atomic_flag::wait/notify_one/notify_all
  * atomic::wait/notify_one/notify_all
  * counting_semaphore
  * binary_semaphore
  * latch

libstdc++-v3/ChangeLog:

	* include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
	(__atomic_flag::notify_one): Likewise.
	(__atomic_flag::notify_all): Likewise.
	(__atomic_base<_Itp>::wait): Likewise.
	(__atomic_base<_Itp>::notify_one): Likewise.
	(__atomic_base<_Itp>::notify_all): Likewise.
	(__atomic_base<_Ptp*>::wait): Likewise.
	(__atomic_base<_Ptp*>::notify_one): Likewise.
	(__atomic_base<_Ptp*>::notify_all): Likewise.
	(__atomic_impl::wait): Likewise.
	(__atomic_impl::notify_one): Likewise.
	(__atomic_impl::notify_all): Likewise.
	(__atomic_float<_Fp>::wait): Likewise.
	(__atomic_float<_Fp>::notify_one): Likewise.
	(__atomic_float<_Fp>::notify_all): Likewise.
	(__atomic_ref<_Tp>::wait): Likewise.
	(__atomic_ref<_Tp>::notify_one): Likewise.
	(__atomic_ref<_Tp>::notify_all): Likewise.
	(atomic_wait<_Tp>): Likewise.
	(atomic_wait_explicit<_Tp>): Likewise.
	(atomic_notify_one<_Tp>): Likewise.
	(atomic_notify_all<_Tp>): Likewise.
	* include/bits/atomic_wait.h: New file.
	* include/bits/atomic_timed_wait.h: New file.
	* include/bits/semaphore_base.h: New file.
	* include/std/atomic (atomic<bool>::wait): Define.
	(atomic<bool>::wait_one): Likewise.
	(atomic<bool>::wait_all): Likewise.
	(atomic<_Tp>::wait): Likewise.
	(atomic<_Tp>::wait_one): Likewise.
	(atomic<_Tp>::wait_all): Likewise.
	(atomic<_Tp*>::wait): Likewise.
	(atomic<_Tp*>::wait_one): Likewise.
	(atomic<_Tp*>::wait_all): Likewise.
	* include/std/latch: New file.
	* include/std/semaphore: New file.
	* include/std/version: Add __cpp_lib_semaphore and
	__cpp_lib_latch defines.
	* testsuite/29_atomic/atomic/wait_notify/bool.cc: New test.
	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
	* testsuite/29_atomic/atomic_float/wait_notify.cc: Likewise.
	* testsuite/29_atomic/atomic_integral/wait_notify.cc: Likewise.
	* testsuite/29_atomic/atomic_ref/wait_notify.cc: Likewise.
	* testsuite/30_thread/semaphore/1.cc: New test.
	* testsuite/30_thread/semaphore/2.cc: Likewise.
	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
	* testsuite/30_thread/latch/1.cc: New test.
	* testsuite/30_thread/latch/2.cc: New test.
	* testsuite/30_thread/latch/3.cc: New test.
	* testsuite/util/atomic/wait_notify_util.h: New File.

---
 libstdc++-v3/include/Makefile.am                   |   5 +
 libstdc++-v3/include/Makefile.in                   |   5 +
 libstdc++-v3/include/bits/atomic_base.h            | 195 ++++++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h      | 288 +++++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h            | 306 +++++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h         | 298 ++++++++++++++++++++
 libstdc++-v3/include/std/atomic                    |  78 ++++++
 libstdc++-v3/include/std/latch                     |  91 ++++++
 libstdc++-v3/include/std/semaphore                 |  92 +++++++
 libstdc++-v3/include/std/version                   |   2 +
 .../29_atomics/atomic/wait_notify/bool.cc          |  59 ++++
 .../29_atomics/atomic/wait_notify/generic.cc       |  31 +++
 .../29_atomics/atomic/wait_notify/pointers.cc      |  59 ++++
 .../29_atomics/atomic_flag/wait_notify/1.cc        |  61 ++++
 .../29_atomics/atomic_float/wait_notify.cc         |  32 +++
 .../29_atomics/atomic_integral/wait_notify.cc      |  65 +++++
 .../testsuite/29_atomics/atomic_ref/wait_notify.cc | 103 +++++++
 libstdc++-v3/testsuite/30_threads/latch/1.cc       |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/2.cc       |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/3.cc       |  69 +++++
 libstdc++-v3/testsuite/30_threads/semaphore/1.cc   |  27 ++
 libstdc++-v3/testsuite/30_threads/semaphore/2.cc   |  27 ++
 .../30_threads/semaphore/least_max_value_neg.cc    |  30 ++
 .../testsuite/30_threads/semaphore/try_acquire.cc  |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc        |  85 ++++++
 .../30_threads/semaphore/try_acquire_posix.cc      | 153 +++++++++++
 .../30_threads/semaphore/try_acquire_until.cc      |  94 +++++++
 .../testsuite/util/atomic/wait_notify_util.h       | 160 +++++++++++
 28 files changed, 2523 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
 create mode 100644 libstdc++-v3/include/std/latch
 create mode 100644 libstdc++-v3/include/std/semaphore
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
 create mode 100644 libstdc++-v3/testsuite/util/atomic/wait_notify_util.h

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..784e4426a06 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch \
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
 	${std_srcdir}/scoped_allocator \
+	${std_srcdir}/semaphore \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
 	${std_srcdir}/span \
@@ -102,6 +104,8 @@ bits_headers = \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
 	${bits_srcdir}/atomic_futex.h \
+	${bits_srcdir}/atomic_timed_wait.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
 	${bits_srcdir}/basic_string.h \
@@ -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..cd5b6aabc44
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,288 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class __atomic_wait_status { no_timeout, timeout };
+
+  namespace __detail
+  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    using __platform_wait_clock_t = chrono::steady_clock;
+
+    template<typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until_impl(__platform_wait_t* __addr,
+				 __platform_wait_t __val,
+				 const chrono::time_point<
+					  __platform_wait_clock_t, _Duration>&
+				      __atime) noexcept
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	struct timespec __rt =
+	{
+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
+	  static_cast<long>(__ns.count())
+	};
+
+	auto __e = syscall (SYS_futex, __addr,
+			    static_cast<int>(__futex_wait_flags::
+						__wait_bitset_private),
+			    __val, &__rt, nullptr,
+			    static_cast<int>(__futex_wait_flags::
+						__bitset_match_any));
+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+	    std::terminate();
+	return (__platform_wait_clock_t::now() < __atime)
+	       ? __atomic_wait_status::no_timeout
+	       : __atomic_wait_status::timeout;
+      }
+
+    template<typename _Clock, typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+			    const chrono::time_point<_Clock, _Duration>&
+				__atime)
+      {
+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __detail::__platform_wait_until_impl(__addr, __val, __atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __platform_wait_clock_t::time_point __s_entry =
+		    __platform_wait_clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (__detail::__platform_wait_until_impl(__addr, __val, __s_atime)
+		  == __atomic_wait_status::no_timeout)
+	      return __atomic_wait_status::no_timeout;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    if (_Clock::now() < __atime)
+	      return __atomic_wait_status::no_timeout;
+	    return __atomic_wait_status::timeout;
+	  }
+      }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Duration>
+      __atomic_wait_status
+      __cond_wait_until_impl(__gthread_cond_t* __cv,
+	  unique_lock<mutex>& __lock,
+	  const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	__gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+			       CLOCK_MONOTONIC,
+			       &__ts);
+	return (chrono::steady_clock::now() < __atime)
+	       ? __atomic_wait_status::no_timeout
+	       : __atomic_wait_status::timeout;
+      }
+#endif
+
+      template<typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until_impl(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+	{
+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	  __gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	  __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+				   &__ts);
+	  return (chrono::system_clock::now() < __atime)
+		 ? __atomic_wait_status::no_timeout
+		 : __atomic_wait_status::timeout;
+	}
+
+      // return true if timeout
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+	  using __clock_t = chrono::steady_clock;
+#else
+	  using __clock_t = chrono::system_clock;
+#endif
+	  const typename _Clock::time_point __c_entry = _Clock::now();
+	  const __clock_t::time_point __s_entry = __clock_t::now();
+	  const auto __delta = __atime - __c_entry;
+	  const auto __s_atime = __s_entry + __delta;
+	  if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+	    return __atomic_wait_status::no_timeout;
+	  // We got a timeout when measured against __clock_t but
+	  // we need to check against the caller-supplied clock
+	  // to tell whether we should return a timeout.
+	  if (_Clock::now() < __atime)
+	    return __atomic_wait_status::no_timeout;
+	  return __atomic_wait_status::timeout;
+	}
+
+    struct __timed_waiters : __waiters
+    {
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	_M_do_wait_until(__platform_wait_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	  return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+	  __platform_wait_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (__detail::__cond_wait_until(&_M_cv, __l, __atime)
+		    == __atomic_wait_status::timeout)
+		return __atomic_wait_status::timeout;
+
+	      __platform_wait_t __last = __cur;
+	      __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	      if (__cur < __last)
+		break; // break the loop if version overflows
+	    }
+	  return __atomic_wait_status::no_timeout;
+#endif
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+      }
+    };
+  } // namespace __detail
+
+  template<typename _Tp, typename _Pred,
+	   typename _Clock, typename _Duration>
+    bool
+    __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+			const chrono::time_point<_Clock, _Duration>&
+			    __atime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+      auto __version = __w._M_enter_wait();
+      do
+	{
+	  __atomic_wait_status __res;
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __res = __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..30f682e828a
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,306 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    constexpr auto __atomic_spin_count_1 = 16;
+    constexpr auto __atomic_spin_count_2 = 12;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+    template<typename _Tp>
+      inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	= is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+	= false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum class __futex_wait_flags : int
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __private_flag = 128,
+#else
+      __private_flag = 0,
+#endif
+      __wait = 0,
+      __wake = 1,
+      __wait_bitset = 9,
+      __wake_bitset = 10,
+      __wait_private = __wait | __private_flag,
+      __wake_private = __wake | __private_flag,
+      __wait_bitset_private = __wait_bitset | __private_flag,
+      __wake_bitset_private = __wake_bitset | __private_flag,
+      __bitset_match_any = -1
+    };
+
+    template<typename _Tp>
+      void
+      __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+      {
+	for(;;)
+	  {
+	    auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+				  static_cast<int>(__futex_wait_flags::__wait_private),
+				    __val, nullptr);
+	    if (!__e)
+	      break;
+	    else if (!(errno == EINTR || errno == EAGAIN))
+	      __throw_system_error(__e);
+	  }
+      }
+
+      template<typename _Tp>
+      void
+      __platform_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	syscall (SYS_futex, static_cast<const void*>(__addr),
+		  static_cast<int>(__futex_wait_flags::__wake_private),
+		    __all ? INT_MAX : 1);
+      }
+#endif
+
+    struct __waiters
+    {
+       alignas(64) __platform_wait_t _M_ver = 0;
+       alignas(64) __platform_wait_t _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#  ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#  else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#  endif
+#endif
+
+      __platform_wait_t
+      _M_enter_wait() noexcept
+      {
+	__platform_wait_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(__platform_wait_t __version) noexcept
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_wait(&_M_ver, __version);
+#else
+	__platform_wait_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      __throw_system_error(__e);
+	    __platform_wait_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+#endif
+      }
+
+      bool
+      _M_waiting() const noexcept
+	{
+	  __platform_wait_t __res;
+	  __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+	  return __res;
+	}
+
+      void
+      _M_notify(bool __all) noexcept
+      {
+	__atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_notify(&_M_ver, __all);
+#else
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+#endif
+      }
+
+      static __waiters&
+      _S_for(const void* __t)
+      {
+	const unsigned char __mask = 0xf;
+	static __waiters __w[__mask + 1];
+
+	auto __key = _Hash_impl::hash(__t) & __mask;
+	return __w[__key];
+      }
+    };
+
+    struct __waiter
+    {
+      __waiters& _M_w;
+      __platform_wait_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+	  , _M_version(_M_w._M_enter_wait())
+	{ }
+
+      ~__waiter()
+      { _M_w._M_leave_wait(); }
+
+      void _M_do_wait() noexcept
+      { _M_w._M_do_wait(_M_version); }
+    };
+
+    void
+    __thread_relax() noexcept
+    {
+#if defined __i386__ || defined __x86_64__
+      __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    void
+    __thread_yield() noexcept
+   {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+     __gthread_yield();
+#endif
+    }
+
+  } // namespace __detail
+
+  template<typename _Pred>
+    bool
+    __atomic_spin(_Pred& __pred) noexcept
+    {
+      for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < __detail::__atomic_spin_count_2)
+	    __detail::__thread_relax();
+	  else
+	    __detail::__thread_yield();
+	}
+      return false;
+    }
+
+  template<typename _Tp, typename _Pred>
+    void
+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+    {
+      using namespace __detail;
+      if (__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..a32a6b12a1b
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,298 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#include <ext/numeric_traits.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+#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_assert(__gnu_cxx::__int_traits<_Tp>::__max
+			<= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+	explicit __atomic_semaphore(_Tp __count) noexcept
+	  : _M_counter(__count)
+	{
+	  __glibcxx_assert(__count >= 0 && __count <= _S_max);
+	}
+
+	__atomic_semaphore(const __atomic_semaphore&) = delete;
+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+	_GLIBCXX_ALWAYS_INLINE void
+	_M_acquire() noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_counter,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+	  __atomic_wait(&_M_counter, __old, __pred);
+	}
+
+	bool
+	_M_try_acquire() noexcept
+	{
+	  auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
+	  auto const __pred = [this, __old]
+	    {
+	      if (__old == 0)
+		return false;
+
+	      auto __prev = __old;
+	      return __atomic_impl::compare_exchange_weak(&this->_M_counter,
+			__prev, __prev - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  return __atomic_spin(__pred);
+	}
+
+	template<typename _Clock, typename _Duration>
+	  _GLIBCXX_ALWAYS_INLINE bool
+	  _M_try_acquire_until(const chrono::time_point<_Clock,
+			       _Duration>& __atime) noexcept
+	  {
+	    auto const __pred = [this]
+	      {
+		auto __old = __atomic_impl::load(&this->_M_counter,
+				memory_order::acquire);
+		if (__old == 0)
+		  return false;
+		return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+				__old, __old - 1,
+				memory_order::acquire,
+				memory_order::release);
+	      };
+
+	    auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+	    return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
+	}
+
+      template<typename _Rep, typename _Period>
+	_GLIBCXX_ALWAYS_INLINE bool
+	_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
+	  noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_counter,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return  __atomic_impl::compare_exchange_strong(&this->_M_counter,
+			      __old, __old - 1,
+			      memory_order::acquire,
+			      memory_order::release);
+	    };
+
+	  auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+	  return __atomic_wait_for(&_M_counter, __old, __pred, __rtime);
+	}
+
+      _GLIBCXX_ALWAYS_INLINE void
+      _M_release(ptrdiff_t __update) noexcept
+      {
+	if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
+	  return;
+	if (__update > 1)
+	  __atomic_impl::notify_all(&_M_counter);
+	else
+	  __atomic_impl::notify_one(&_M_counter);
+      }
+
+    private:
+      alignas(__alignof__(_Tp)) _Tp _M_counter;
+    };
+
+// Note: the _GLIBCXX_REQUIRE_POSIX_SEMAPHORE macro can be used to force the
+// use of Posix semaphores (sem_t). Doing so however, alters the ABI.
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+  // Use futex if available and didn't force use of POSIX
+  using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  using __fast_semaphore = __platform_semaphore;
+#else
+  using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+  using __semaphore_impl = conditional_t<
+		(__least_max_value > 1),
+		conditional_t<
+		    (__least_max_value <= __fast_semaphore::_S_max),
+		    __fast_semaphore,
+		    __atomic_semaphore<ptrdiff_t>>,
+		__fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..5afe33b41d9 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     compare_exchange_strong(bool& __i1, bool __i2,
 		    memory_order __m = memory_order_seq_cst) volatile noexcept
     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const
+      noexcept
+    { _M_base.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_base.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_base.notify_all(); }
+#endif
   };
 
 #if __cplusplus <= 201703L
@@ -363,6 +377,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     memory_order __m = memory_order_seq_cst) volatile noexcept
       { return compare_exchange_strong(__e, __i, __m,
                                        __cmpexch_failure_order(__m)); }
+
+#if __cplusplus > 201703L
+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]
+			 {
+			   const auto __v = this->load(__m);
+			   // TODO make this ignore padding bits when we
+			   // can do that
+			   return __builtin_memcmp(&__old, &__v,
+						    sizeof(_Tp)) != 0;
+			 });
+    }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    void notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -601,6 +639,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					    __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+    void wait(__pointer_type __old,
+	      memory_order __m = memory_order_seq_cst) noexcept
+    { _M_b.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_b.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_b.notify_all(); }
+#endif
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1404,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 						     memory_order_seq_cst);
     }
 
+
+#if __cplusplus > 201703L
+  template<typename _Tp>
+    inline void
+    atomic_wait(const atomic<_Tp>* __a,
+	        typename std::atomic<_Tp>::value_type __old) noexcept
+    { __a->wait(__old); }
+
+  template<typename _Tp>
+    inline void
+    atomic_wait_explicit(const atomic<_Tp>* __a,
+			 typename std::atomic<_Tp>::value_type __old,
+			 std::memory_order __m) noexcept
+    { __a->wait(__old, __m); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_one(atomic<_Tp>* __a) noexcept
+    { __a->notify_one(); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_all(atomic<_Tp>* __a) noexcept
+    { __a->notify_all(); }
+
+#endif // C++2a
+
   // Function templates for atomic_integral and atomic_pointer operations only.
   // Some operations (and, or, xor) are only available for atomic integrals,
   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..9725a68040c
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,91 @@
+// <latch> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class latch
+  {
+  public:
+    static constexpr ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__int_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) noexcept
+      : _M_a(__expected) { }
+
+    ~latch() = default;
+    latch(const latch&) = delete;
+    latch& operator=(const latch&) = delete;
+
+    _GLIBCXX_ALWAYS_INLINE void
+    count_down(ptrdiff_t __update = 1)
+    {
+      auto const __old = __atomic_impl::fetch_sub(&_M_a,
+				    __update, memory_order::release);
+      if (__old == __update)
+	__atomic_impl::notify_all(&_M_a);
+    }
+
+    _GLIBCXX_ALWAYS_INLINE bool
+    try_wait() const noexcept
+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait() const noexcept
+    {
+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+      __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    arrive_and_wait(ptrdiff_t __update = 1) noexcept
+    {
+      count_down(__update);
+      wait();
+    }
+
+  private:
+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+  };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..b4facde4ea1
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<ptrdiff_t __least_max_value =
+			__gnu_cxx::__int_traits<ptrdiff_t>::__max>
+    class counting_semaphore
+    {
+      static_assert(__least_max_value >= 0);
+
+      __semaphore_impl<__least_max_value> _M_sem;
+
+    public:
+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
+	: _M_sem(__desired)
+      { }
+
+      ~counting_semaphore() = default;
+
+      counting_semaphore(const counting_semaphore&) = delete;
+      counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+      static constexpr ptrdiff_t
+      max() noexcept
+      { return __least_max_value; }
+
+      void
+      release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+      { _M_sem._M_release(__update); }
+
+      void
+      acquire() noexcept(noexcept(_M_sem._M_acquire()))
+      { _M_sem._M_acquire(); }
+
+      bool
+      try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+      { return _M_sem._M_try_acquire(); }
+
+      template<typename _Rep, typename _Period>
+	bool
+	try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+	{ return _M_sem._M_try_acquire_for(__rtime); }
+
+      template<typename _Clock, typename _Dur>
+	bool
+	try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+	{ return _M_sem._M_try_acquire_until(__atime); }
+    };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 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/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/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..0249341055c
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "atomic/wait_notify_util.h"
+
+int
+main ()
+{
+  struct S{ int i; };
+  check<S> check_s{S{0},S{42}};
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  long aa;
+  long bb;
+
+  std::atomic<long*> a(nullptr);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(nullptr);
+		  if (a.load() == &aa)
+		    a.store(&bb);
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(&aa);
+  a.notify_one();
+  t.join();
+  VERIFY( a.load() == &bb);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..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/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
new file mode 100644
index 00000000000..b46eb603304
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "atomic/wait_notify_util.h"
+
+int
+main ()
+{
+  check<float> f;
+  check<double> d;
+  check<long double> l;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
new file mode 100644
index 00000000000..6e9ee7dbf93
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "atomic/wait_notify_util.h"
+
+void
+test01()
+{
+  struct S{ int i; };
+  std::atomic<S> s;
+
+  s.wait(S{42});
+}
+
+int
+main ()
+{
+  // check<bool> bb;
+  check<char> ch;
+  check<signed char> sch;
+  check<unsigned char> uch;
+  check<short> s;
+  check<unsigned short> us;
+  check<int> i;
+  check<unsigned int> ui;
+  check<long> l;
+  check<unsigned long> ul;
+  check<long long> ll;
+  check<unsigned long long> ull;
+
+  check<wchar_t> wch;
+  check<char8_t> ch8;
+  check<char16_t> ch16;
+  check<char32_t> ch32;
+
+  check<int8_t> i8;
+  check<int16_t> i16;
+  check<int32_t> i32;
+  check<int64_t> i64;
+
+  check<uint8_t> u8;
+  check<uint16_t> u16;
+  check<uint32_t> u32;
+  check<uint64_t> u64;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  Tp aa = val1;
+  std::atomic_ref<Tp> a(aa);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp,
+	 bool = std::is_integral_v<Tp>
+	 || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+  check(Tp b)
+  {
+    Tp a;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+struct foo
+{
+  long a = 0;
+  long b = 0;
+
+  foo& operator=(foo const&) = default;
+
+  friend bool
+  operator==(foo const& rhs, foo const& lhs)
+  { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+  check<long>();
+  check<double>();
+  check<foo>({42, 48});
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..5d08000f430
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
+
+void
+test02()
+{
+  std::latch l(3);
+  std::thread t([&]
+    {
+      l.count_down();
+    });
+
+  l.arrive_and_wait(2);
+  t.join();
+  VERIFY( l.try_wait() );
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
@@ -0,0 +1,160 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+  check(Tp a = 0, Tp b = 42)
+  {
+    if constexpr (std::equality_comparable<Tp>)
+    {
+      VERIFY( check_wait_notify(a, b) == b);
+      VERIFY( check_atomic_wait_notify(a, b) == b);
+    }
+    else
+    {
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+      }
+
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_atomic_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+      }
+    }
+  }
+};

-- 
tg: (64a5fb5f438..) t/trodgers/c2a_synchronization (depends on: master)


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] t/trodgers/c2a_synchronization
  2020-10-05 22:54                       ` [PATCH] t/trodgers/c2a_synchronization Thomas Rodgers
@ 2020-10-23 10:28                         ` Jonathan Wakely
  2020-10-26 21:48                           ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
  0 siblings, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-10-23 10:28 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 05/10/20 15:54 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This *should* be the correct patch this time.

There are still some review comments not addressed. I'll keep all my
comments on this version in a single reply, so they aren't lost among
multiple replies.

I think the significant issues like the handling of spurious wakeups
and the missing "no effects" case in _M_try_acquire() are resolved,
thanks.

>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..cd5b6aabc44
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h

[...]

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

Qualify to prevent ADL in associated namespaces of the _Clock and
_Duration types.

>+  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,

Qualify to prevent ADL.


>diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
>new file mode 100644
>index 00000000000..30f682e828a
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_wait.h


>+  template<typename _Tp, typename _Pred>
>+    void
>+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
>+    {
>+      using namespace __detail;
>+      if (__atomic_spin(__pred))

Qualify to prevent ADL.

>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>new file mode 100644
>index 00000000000..a32a6b12a1b
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>@@ -0,0 +1,298 @@
>+// -*- C++ -*- header.
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/semaphore_base.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{semaphore}
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
>+#define _GLIBCXX_SEMAPHORE_BASE_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/atomic_base.h>
>+#include <bits/atomic_timed_wait.h>
>+
>+#include <ext/numeric_traits.h>
>+
>+#if __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
>+#endif
>+
>+#include <chrono>
>+#include <type_traits>
>+
>+#include <iostream>

This shouldn't be here.

>+
>+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;

It looks like this would be simpler with just one check for __err:

       auto __err = sem_timedwait(&_M_semaphore, &__ts);
       if (__err)
         {
           if (errno == EINTR)
             continue;
           if (errno == ETIMEDOUT || errno == EINVAL)
             return false;
           else
             std::terminate();
         }
       else
         break;

Hopefully the compiler wouldn't actually keep testing __err but I think
it reads better this way anyway.


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

is_same_v (it's not just stylistic, the variable template is faster to
compile than the class template).

>+	  {
>+	    return _M_try_acquire_until_impl(__atime);
>+	  }
>+	else
>+	  {
>+	    const typename _Clock::time_point __c_entry = _Clock::now();
>+	    const __clock_t __s_entry = __clock_t::now();
>+	    const auto __delta = __atime - __c_entry;
>+	    const auto __s_atime = __s_entry + __delta;
>+	    if (_M_try_acquire_until_impl(__s_atime))
>+	      return true;
>+
>+	    // We got a timeout when measured against __clock_t but
>+	    // we need to check against the caller-supplied clock
>+	    // to tell whether we should return a timeout.
>+	    return (_Clock::now() < __atime);
>+	  }
>+      }
>+
>+    template<typename _Rep, typename _Period>
>+      _GLIBCXX_ALWAYS_INLINE bool
>+      _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
>+	noexcept
>+      { return _M_try_acquire_until(__clock_t::now() + __rtime); }
>+
>+    private:
>+      sem_t _M_semaphore;
>+    };
>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+
>+    template<typename _Tp>
>+      struct __atomic_semaphore
>+      {
>+	static_assert(std::is_integral_v<_Tp>);
>+	static_assert(__gnu_cxx::__int_traits<_Tp>::__max
>+			<= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
>+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
>+
>+	explicit __atomic_semaphore(_Tp __count) noexcept
>+	  : _M_counter(__count)
>+	{
>+	  __glibcxx_assert(__count >= 0 && __count <= _S_max);
>+	}
>+
>+	__atomic_semaphore(const __atomic_semaphore&) = delete;
>+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
>+
>+	_GLIBCXX_ALWAYS_INLINE void
>+	_M_acquire() noexcept
>+	{
>+	  auto const __pred = [this]
>+	    {
>+	      auto __old = __atomic_impl::load(&this->_M_counter,
>+			      memory_order::acquire);
>+	      if (__old == 0)
>+		return false;
>+	      return __atomic_impl::compare_exchange_strong(&this->_M_counter,
>+			__old, __old - 1,
>+			memory_order::acquire,
>+			memory_order::release);
>+	    };
>+	  auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
>+	  __atomic_wait(&_M_counter, __old, __pred);

Qualify to prevent ADL.


>--- /dev/null
>+++ b/libstdc++-v3/include/std/latch
>@@ -0,0 +1,91 @@
>+// <latch> -*- C++ -*-
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.	This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/latch
>+ *  This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_LATCH
>+#define _GLIBCXX_LATCH
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_latch 201907L
>+
>+#include <bits/atomic_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  class latch
>+  {
>+  public:
>+    static constexpr ptrdiff_t
>+    max() noexcept
>+    { return __gnu_cxx::__int_traits<ptrdiff_t>::__max; }
>+
>+    constexpr explicit latch(ptrdiff_t __expected) noexcept
>+      : _M_a(__expected) { }
>+
>+    ~latch() = default;
>+    latch(const latch&) = delete;
>+    latch& operator=(const latch&) = delete;
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    count_down(ptrdiff_t __update = 1)
>+    {
>+      auto const __old = __atomic_impl::fetch_sub(&_M_a,
>+				    __update, memory_order::release);
>+      if (__old == __update)
>+	__atomic_impl::notify_all(&_M_a);
>+    }
>+
>+    _GLIBCXX_ALWAYS_INLINE bool
>+    try_wait() const noexcept
>+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    wait() const noexcept
>+    {
>+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
>+      __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });

Qualify to prevent ADL.

>+    }
>+
>+    _GLIBCXX_ALWAYS_INLINE void
>+    arrive_and_wait(ptrdiff_t __update = 1) noexcept
>+    {
>+      count_down(__update);
>+      wait();
>+    }
>+
>+  private:
>+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
>+  };
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_LATCH


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] libstdc++: Add C++2a synchronization support
  2020-10-23 10:28                         ` Jonathan Wakely
@ 2020-10-26 21:48                           ` Thomas Rodgers
  2020-10-27 10:23                             ` Jonathan Wakely
  2020-11-21 15:16                             ` Andreas Schwab
  0 siblings, 2 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-10-26 21:48 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers

From: Thomas Rodgers <trodgers@redhat.com>

Add support for -
  * atomic_flag::wait/notify_one/notify_all
  * atomic::wait/notify_one/notify_all
  * counting_semaphore
  * binary_semaphore
  * latch

libstdc++-v3/ChangeLog:

	* include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_flag::wait): Define.
	(__atomic_flag::notify_one): Likewise.
	(__atomic_flag::notify_all): Likewise.
	(__atomic_base<_Itp>::wait): Likewise.
	(__atomic_base<_Itp>::notify_one): Likewise.
	(__atomic_base<_Itp>::notify_all): Likewise.
	(__atomic_base<_Ptp*>::wait): Likewise.
	(__atomic_base<_Ptp*>::notify_one): Likewise.
	(__atomic_base<_Ptp*>::notify_all): Likewise.
	(__atomic_impl::wait): Likewise.
	(__atomic_impl::notify_one): Likewise.
	(__atomic_impl::notify_all): Likewise.
	(__atomic_float<_Fp>::wait): Likewise.
	(__atomic_float<_Fp>::notify_one): Likewise.
	(__atomic_float<_Fp>::notify_all): Likewise.
	(__atomic_ref<_Tp>::wait): Likewise.
	(__atomic_ref<_Tp>::notify_one): Likewise.
	(__atomic_ref<_Tp>::notify_all): Likewise.
	(atomic_wait<_Tp>): Likewise.
	(atomic_wait_explicit<_Tp>): Likewise.
	(atomic_notify_one<_Tp>): Likewise.
	(atomic_notify_all<_Tp>): Likewise.
	* include/bits/atomic_wait.h: New file.
	* include/bits/atomic_timed_wait.h: New file.
	* include/bits/semaphore_base.h: New file.
	* include/std/atomic (atomic<bool>::wait): Define.
	(atomic<bool>::wait_one): Likewise.
	(atomic<bool>::wait_all): Likewise.
	(atomic<_Tp>::wait): Likewise.
	(atomic<_Tp>::wait_one): Likewise.
	(atomic<_Tp>::wait_all): Likewise.
	(atomic<_Tp*>::wait): Likewise.
	(atomic<_Tp*>::wait_one): Likewise.
	(atomic<_Tp*>::wait_all): Likewise.
	* include/std/latch: New file.
	* include/std/semaphore: New file.
	* include/std/version: Add __cpp_lib_semaphore and
	__cpp_lib_latch defines.
	* testsuite/29_atomic/atomic/wait_notify/bool.cc: New test.
	* testsuite/29_atomic/atomic/wait_notify/pointers.cc: Likewise.
	* testsuite/29_atomic/atomic/wait_notify/generic.cc: Liekwise.
	* testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
	* testsuite/29_atomic/atomic_float/wait_notify.cc: Likewise.
	* testsuite/29_atomic/atomic_integral/wait_notify.cc: Likewise.
	* testsuite/29_atomic/atomic_ref/wait_notify.cc: Likewise.
	* testsuite/30_thread/semaphore/1.cc: New test.
	* testsuite/30_thread/semaphore/2.cc: Likewise.
	* testsuite/30_thread/semaphore/least_max_value_neg.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_for.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_posix.cc: Likewise.
	* testsuite/30_thread/semaphore/try_acquire_until.cc: Likewise.
	* testsuite/30_thread/latch/1.cc: New test.
	* testsuite/30_thread/latch/2.cc: New test.
	* testsuite/30_thread/latch/3.cc: New test.
	* testsuite/util/atomic/wait_notify_util.h: New File.
---
 libstdc++-v3/include/Makefile.am              |   5 +
 libstdc++-v3/include/Makefile.in              |   5 +
 libstdc++-v3/include/bits/atomic_base.h       | 195 ++++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 287 ++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 306 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 296 +++++++++++++++++
 libstdc++-v3/include/std/atomic               |  78 +++++
 libstdc++-v3/include/std/latch                |  91 ++++++
 libstdc++-v3/include/std/semaphore            |  92 ++++++
 libstdc++-v3/include/std/version              |   2 +
 .../29_atomics/atomic/wait_notify/bool.cc     |  59 ++++
 .../29_atomics/atomic/wait_notify/generic.cc  |  31 ++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 .../29_atomics/atomic_flag/wait_notify/1.cc   |  61 ++++
 .../29_atomics/atomic_float/wait_notify.cc    |  32 ++
 .../29_atomics/atomic_integral/wait_notify.cc |  65 ++++
 .../29_atomics/atomic_ref/wait_notify.cc      | 103 ++++++
 libstdc++-v3/testsuite/30_threads/latch/1.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/2.cc  |  27 ++
 libstdc++-v3/testsuite/30_threads/latch/3.cc  |  69 ++++
 .../testsuite/30_threads/semaphore/1.cc       |  27 ++
 .../testsuite/30_threads/semaphore/2.cc       |  27 ++
 .../semaphore/least_max_value_neg.cc          |  30 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_posix.cc | 153 +++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 .../testsuite/util/atomic/wait_notify_util.h  | 160 +++++++++
 28 files changed, 2520 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_timed_wait.h
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/include/bits/semaphore_base.h
 create mode 100644 libstdc++-v3/include/std/latch
 create mode 100644 libstdc++-v3/include/std/semaphore
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/latch/3.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/1.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/2.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
 create mode 100644 libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
 create mode 100644 libstdc++-v3/testsuite/util/atomic/wait_notify_util.h

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c90ac555e15..382e94322c1 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch \
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
 	${std_srcdir}/scoped_allocator \
+	${std_srcdir}/semaphore \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
 	${std_srcdir}/span \
@@ -102,6 +104,8 @@ bits_headers = \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
 	${bits_srcdir}/atomic_futex.h \
+	${bits_srcdir}/atomic_timed_wait.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
 	${bits_srcdir}/basic_string.h \
@@ -177,6 +181,7 @@ bits_headers = \
 	${bits_srcdir}/regex_compiler.tcc \
 	${bits_srcdir}/regex_executor.h \
 	${bits_srcdir}/regex_executor.tcc \
+	${bits_srcdir}/semaphore_base.h \
 	${bits_srcdir}/shared_ptr.h \
 	${bits_srcdir}/shared_ptr_atomic.h \
 	${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __atomic_load(&_M_i, &__v, int(__m));
       return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
     }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait(bool __old,
+	memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]()
+			 { return this->test(__m) != __old; });
+    }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+
+    // TODO add const volatile overload
 #endif // C++20
 
     _GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__int_type __old,
+	  memory_order __m = memory_order_seq_cst) const noexcept
+      {
+	std::__atomic_wait(&_M_i, __old,
+			   [__m, this, __old]
+			   { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_i, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_i, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __int_type
       fetch_add(__int_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					   int(__m1), int(__m2));
       }
 
+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__pointer_type __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(&_M_p, __old,
+		      [__m, this, __old]()
+		      { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_p, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_p, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
       _GLIBCXX_ALWAYS_INLINE __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					 int(__success), int(__failure));
       }
 
+#if __cplusplus > 201703L
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(const _Tp* __ptr, _Val<_Tp> __old,
+	   memory_order __m = memory_order_seq_cst) noexcept
+      {
+	std::__atomic_wait(__ptr, __old,
+	    [=]() { return load(__ptr, __m) == __old; });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, false); }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
     template<typename _Tp>
       _GLIBCXX_ALWAYS_INLINE _Tp
       fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(&_M_fp); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(&_M_fp); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
     private:
       _Tp* _M_ptr;
     };
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				       __cmpexch_failure_order(__order));
       }
 
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
       _GLIBCXX_ALWAYS_INLINE value_type
       fetch_add(difference_type __d,
 		memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..7712a6c591d
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,287 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class __atomic_wait_status { no_timeout, timeout };
+
+  namespace __detail
+  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    using __platform_wait_clock_t = chrono::steady_clock;
+
+    template<typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until_impl(__platform_wait_t* __addr,
+				 __platform_wait_t __val,
+				 const chrono::time_point<
+					  __platform_wait_clock_t, _Duration>&
+				      __atime) noexcept
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	struct timespec __rt =
+	{
+	  static_cast<std::time_t>(__s.time_since_epoch().count()),
+	  static_cast<long>(__ns.count())
+	};
+
+	auto __e = syscall (SYS_futex, __addr,
+			    static_cast<int>(__futex_wait_flags::
+						__wait_bitset_private),
+			    __val, &__rt, nullptr,
+			    static_cast<int>(__futex_wait_flags::
+						__bitset_match_any));
+	if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+	    std::terminate();
+	return (__platform_wait_clock_t::now() < __atime)
+	       ? __atomic_wait_status::no_timeout
+	       : __atomic_wait_status::timeout;
+      }
+
+    template<typename _Clock, typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+			    const chrono::time_point<_Clock, _Duration>&
+				__atime)
+      {
+	if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __detail::__platform_wait_until_impl(__addr, __val, __atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __platform_wait_clock_t::time_point __s_entry =
+		    __platform_wait_clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (__detail::__platform_wait_until_impl(__addr, __val, __s_atime)
+		  == __atomic_wait_status::no_timeout)
+	      return __atomic_wait_status::no_timeout;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    if (_Clock::now() < __atime)
+	      return __atomic_wait_status::no_timeout;
+	    return __atomic_wait_status::timeout;
+	  }
+      }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Duration>
+      __atomic_wait_status
+      __cond_wait_until_impl(__gthread_cond_t* __cv,
+	  unique_lock<mutex>& __lock,
+	  const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
+      {
+	auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	__gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+			       CLOCK_MONOTONIC,
+			       &__ts);
+	return (chrono::steady_clock::now() < __atime)
+	       ? __atomic_wait_status::no_timeout
+	       : __atomic_wait_status::timeout;
+      }
+#endif
+
+      template<typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until_impl(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+	{
+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+	  __gthread_time_t __ts =
+	  {
+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
+	    static_cast<long>(__ns.count())
+	  };
+
+	  __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+				   &__ts);
+	  return (chrono::system_clock::now() < __atime)
+		 ? __atomic_wait_status::no_timeout
+		 : __atomic_wait_status::timeout;
+	}
+
+      // return true if timeout
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	__cond_wait_until(__gthread_cond_t* __cv,
+	    unique_lock<std::mutex>& __lock,
+	    const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+	  using __clock_t = chrono::steady_clock;
+#else
+	  using __clock_t = chrono::system_clock;
+#endif
+	  const typename _Clock::time_point __c_entry = _Clock::now();
+	  const __clock_t::time_point __s_entry = __clock_t::now();
+	  const auto __delta = __atime - __c_entry;
+	  const auto __s_atime = __s_entry + __delta;
+	  if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
+	    return __atomic_wait_status::no_timeout;
+	  // We got a timeout when measured against __clock_t but
+	  // we need to check against the caller-supplied clock
+	  // to tell whether we should return a timeout.
+	  if (_Clock::now() < __atime)
+	    return __atomic_wait_status::no_timeout;
+	  return __atomic_wait_status::timeout;
+	}
+
+    struct __timed_waiters : __waiters
+    {
+      template<typename _Clock, typename _Duration>
+	__atomic_wait_status
+	_M_do_wait_until(__platform_wait_t __version,
+			 const chrono::time_point<_Clock, _Duration>& __atime)
+	{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	  return __detail::__platform_wait_until(&_M_ver, __version, __atime);
+#else
+	  __platform_wait_t __cur = 0;
+	  __waiters::__lock_t __l(_M_mtx);
+	  while (__cur <= __version)
+	    {
+	      if (__detail::__cond_wait_until(&_M_cv, __l, __atime)
+		    == __atomic_wait_status::timeout)
+		return __atomic_wait_status::timeout;
+
+	      __platform_wait_t __last = __cur;
+	      __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	      if (__cur < __last)
+		break; // break the loop if version overflows
+	    }
+	  return __atomic_wait_status::no_timeout;
+#endif
+	}
+
+      static __timed_waiters&
+      _S_timed_for(void* __t)
+      {
+	static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+	return static_cast<__timed_waiters&>(__waiters::_S_for(__t));
+      }
+    };
+  } // namespace __detail
+
+  template<typename _Tp, typename _Pred,
+	   typename _Clock, typename _Duration>
+    bool
+    __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+			const chrono::time_point<_Clock, _Duration>&
+			    __atime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+      auto __version = __w._M_enter_wait();
+      do
+	{
+	  __atomic_wait_status __res;
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __res = __detail::__platform_wait_until((__platform_wait_t*)(void*) __addr,
+						      __old, __atime);
+	    }
+	  else
+	    {
+	      __res = __w._M_do_wait_until(__version, __atime);
+	    }
+	  if (__res == __atomic_wait_status::timeout)
+	    return false;
+	}
+      while (!__pred() && __atime < _Clock::now());
+      __w._M_leave_wait();
+
+      // if timed out, return false
+      return (_Clock::now() < __atime);
+    }
+
+  template<typename _Tp, typename _Pred,
+	   typename _Rep, typename _Period>
+    bool
+    __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+		      const chrono::duration<_Rep, _Period>& __rtime) noexcept
+    {
+      using namespace __detail;
+
+      if (std::__atomic_spin(__pred))
+	return true;
+
+      if (!__rtime.count())
+	return false; // no rtime supplied, and spin did not acquire
+
+      using __dur = chrono::steady_clock::duration;
+      auto __reltime = chrono::duration_cast<__dur>(__rtime);
+      if (__reltime < __rtime)
+	++__reltime;
+
+
+      return __atomic_wait_until(__addr, __old, std::move(__pred),
+				 chrono::steady_clock::now() + __reltime);
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..2d08e5325fb
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,306 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    constexpr auto __atomic_spin_count_1 = 16;
+    constexpr auto __atomic_spin_count_2 = 12;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__int_traits<__platform_wait_t>::__max;
+
+    template<typename _Tp>
+      inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	= is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+	= false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum class __futex_wait_flags : int
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __private_flag = 128,
+#else
+      __private_flag = 0,
+#endif
+      __wait = 0,
+      __wake = 1,
+      __wait_bitset = 9,
+      __wake_bitset = 10,
+      __wait_private = __wait | __private_flag,
+      __wake_private = __wake | __private_flag,
+      __wait_bitset_private = __wait_bitset | __private_flag,
+      __wake_bitset_private = __wake_bitset | __private_flag,
+      __bitset_match_any = -1
+    };
+
+    template<typename _Tp>
+      void
+      __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
+      {
+	for(;;)
+	  {
+	    auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
+				  static_cast<int>(__futex_wait_flags::__wait_private),
+				    __val, nullptr);
+	    if (!__e)
+	      break;
+	    else if (!(errno == EINTR || errno == EAGAIN))
+	      __throw_system_error(__e);
+	  }
+      }
+
+      template<typename _Tp>
+      void
+      __platform_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	syscall (SYS_futex, static_cast<const void*>(__addr),
+		  static_cast<int>(__futex_wait_flags::__wake_private),
+		    __all ? INT_MAX : 1);
+      }
+#endif
+
+    struct __waiters
+    {
+       alignas(64) __platform_wait_t _M_ver = 0;
+       alignas(64) __platform_wait_t _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#  ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#  else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#  endif
+#endif
+
+      __platform_wait_t
+      _M_enter_wait() noexcept
+      {
+	__platform_wait_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(__platform_wait_t __version) noexcept
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_wait(&_M_ver, __version);
+#else
+	__platform_wait_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      __throw_system_error(__e);
+	    __platform_wait_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    if (__cur < __last)
+	      break; // break the loop if version overflows
+	  }
+#endif
+      }
+
+      bool
+      _M_waiting() const noexcept
+	{
+	  __platform_wait_t __res;
+	  __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+	  return __res;
+	}
+
+      void
+      _M_notify(bool __all) noexcept
+      {
+	__atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	__platform_notify(&_M_ver, __all);
+#else
+	auto __e = __gthread_cond_broadcast(&_M_cv);
+	if (__e)
+	  __throw_system_error(__e);
+#endif
+      }
+
+      static __waiters&
+      _S_for(const void* __t)
+      {
+	const unsigned char __mask = 0xf;
+	static __waiters __w[__mask + 1];
+
+	auto __key = _Hash_impl::hash(__t) & __mask;
+	return __w[__key];
+      }
+    };
+
+    struct __waiter
+    {
+      __waiters& _M_w;
+      __platform_wait_t _M_version;
+
+      template<typename _Tp>
+	__waiter(const _Tp* __addr) noexcept
+	  : _M_w(__waiters::_S_for(static_cast<const void*>(__addr)))
+	  , _M_version(_M_w._M_enter_wait())
+	{ }
+
+      ~__waiter()
+      { _M_w._M_leave_wait(); }
+
+      void _M_do_wait() noexcept
+      { _M_w._M_do_wait(_M_version); }
+    };
+
+    void
+    __thread_relax() noexcept
+    {
+#if defined __i386__ || defined __x86_64__
+      __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    void
+    __thread_yield() noexcept
+   {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+     __gthread_yield();
+#endif
+    }
+
+  } // namespace __detail
+
+  template<typename _Pred>
+    bool
+    __atomic_spin(_Pred& __pred) noexcept
+    {
+      for (auto __i = 0; __i < __detail::__atomic_spin_count_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < __detail::__atomic_spin_count_2)
+	    __detail::__thread_relax();
+	  else
+	    __detail::__thread_yield();
+	}
+      return false;
+    }
+
+  template<typename _Tp, typename _Pred>
+    void
+    __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+    {
+      using namespace __detail;
+      if (std::__atomic_spin(__pred))
+	return;
+
+      __waiter __w(__addr);
+      while (!__pred())
+	{
+	  if constexpr (__platform_wait_uses_type<_Tp>)
+	    {
+	      __platform_wait(__addr, __old);
+	    }
+	  else
+	    {
+	      // TODO support timed backoff when this can be moved into the lib
+	      __w._M_do_wait();
+	    }
+	}
+    }
+
+  template<typename _Tp>
+    void
+    __atomic_notify(const _Tp* __addr, bool __all) noexcept
+    {
+      using namespace __detail;
+      auto& __w = __waiters::_S_for((void*)__addr);
+      if (!__w._M_waiting())
+	return;
+
+      if constexpr (__platform_wait_uses_type<_Tp>)
+	{
+	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	}
+      else
+	{
+	  __w._M_notify(__all);
+	}
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
new file mode 100644
index 00000000000..da6dc4b9185
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,296 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/semaphore_base.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{semaphore}
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
+#define _GLIBCXX_SEMAPHORE_BASE_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/atomic_base.h>
+#include <bits/atomic_timed_wait.h>
+
+#include <ext/numeric_traits.h>
+
+#if __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  struct __platform_semaphore
+  {
+    using __clock_t = chrono::system_clock;
+    static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+
+    explicit __platform_semaphore(ptrdiff_t __count) noexcept
+    {
+      sem_init(&_M_semaphore, 0, __count);
+    }
+
+    __platform_semaphore(const __platform_semaphore&) = delete;
+    __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+
+    ~__platform_semaphore()
+    { sem_destroy(&_M_semaphore); }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_acquire() noexcept
+    {
+      for (;;)
+	{
+	  auto __err = sem_wait(&_M_semaphore);
+	  if (__err && (errno == EINTR))
+	    continue;
+	  else if (__err)
+	    std::terminate();
+	  else
+	    break;
+	}
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    _M_release(std::ptrdiff_t __update) noexcept
+    {
+      for(; __update != 0; --__update)
+	{
+	   auto __err = sem_post(&_M_semaphore);
+	   if (__err)
+	     std::terminate();
+	}
+    }
+
+    bool
+    _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime)
+      noexcept
+    {
+
+      auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+      struct timespec __ts =
+      {
+	static_cast<std::time_t>(__s.time_since_epoch().count()),
+	static_cast<long>(__ns.count())
+      };
+
+      for (;;)
+	{
+	  if (auto __err = sem_timedwait(&_M_semaphore, &__ts))
+	    {
+	      if (errno == EINTR)
+		continue;
+	      else if (errno == ETIMEDOUT || errno == EINVAL)
+		return false;
+	      else
+		std::terminate();
+	    }
+	  else
+	    break;
+	}
+      return true;
+    }
+
+    template<typename _Clock, typename _Duration>
+      bool
+      _M_try_acquire_until(const chrono::time_point<_Clock,
+			   _Duration>& __atime) noexcept
+      {
+	if constexpr (std::is_same_v<__clock_t, _Clock>)
+	  {
+	    return _M_try_acquire_until_impl(__atime);
+	  }
+	else
+	  {
+	    const typename _Clock::time_point __c_entry = _Clock::now();
+	    const __clock_t __s_entry = __clock_t::now();
+	    const auto __delta = __atime - __c_entry;
+	    const auto __s_atime = __s_entry + __delta;
+	    if (_M_try_acquire_until_impl(__s_atime))
+	      return true;
+
+	    // We got a timeout when measured against __clock_t but
+	    // we need to check against the caller-supplied clock
+	    // to tell whether we should return a timeout.
+	    return (_Clock::now() < __atime);
+	  }
+      }
+
+    template<typename _Rep, typename _Period>
+      _GLIBCXX_ALWAYS_INLINE bool
+      _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
+	noexcept
+      { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+
+    private:
+      sem_t _M_semaphore;
+    };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	static_assert(std::is_integral_v<_Tp>);
+	static_assert(__gnu_cxx::__int_traits<_Tp>::__max
+			<= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
+	static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
+
+	explicit __atomic_semaphore(_Tp __count) noexcept
+	  : _M_counter(__count)
+	{
+	  __glibcxx_assert(__count >= 0 && __count <= _S_max);
+	}
+
+	__atomic_semaphore(const __atomic_semaphore&) = delete;
+	__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
+
+	_GLIBCXX_ALWAYS_INLINE void
+	_M_acquire() noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_counter,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+			__old, __old - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+	  std::__atomic_wait(&_M_counter, __old, __pred);
+	}
+
+	bool
+	_M_try_acquire() noexcept
+	{
+	  auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
+	  auto const __pred = [this, __old]
+	    {
+	      if (__old == 0)
+		return false;
+
+	      auto __prev = __old;
+	      return __atomic_impl::compare_exchange_weak(&this->_M_counter,
+			__prev, __prev - 1,
+			memory_order::acquire,
+			memory_order::release);
+	    };
+	  return std::__atomic_spin(__pred);
+	}
+
+	template<typename _Clock, typename _Duration>
+	  _GLIBCXX_ALWAYS_INLINE bool
+	  _M_try_acquire_until(const chrono::time_point<_Clock,
+			       _Duration>& __atime) noexcept
+	  {
+	    auto const __pred = [this]
+	      {
+		auto __old = __atomic_impl::load(&this->_M_counter,
+				memory_order::acquire);
+		if (__old == 0)
+		  return false;
+		return __atomic_impl::compare_exchange_strong(&this->_M_counter,
+				__old, __old - 1,
+				memory_order::acquire,
+				memory_order::release);
+	      };
+
+	    auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+	    return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
+	}
+
+      template<typename _Rep, typename _Period>
+	_GLIBCXX_ALWAYS_INLINE bool
+	_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
+	  noexcept
+	{
+	  auto const __pred = [this]
+	    {
+	      auto __old = __atomic_impl::load(&this->_M_counter,
+			      memory_order::acquire);
+	      if (__old == 0)
+		return false;
+	      return  __atomic_impl::compare_exchange_strong(&this->_M_counter,
+			      __old, __old - 1,
+			      memory_order::acquire,
+			      memory_order::release);
+	    };
+
+	  auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
+	  return __atomic_wait_for(&_M_counter, __old, __pred, __rtime);
+	}
+
+      _GLIBCXX_ALWAYS_INLINE void
+      _M_release(ptrdiff_t __update) noexcept
+      {
+	if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
+	  return;
+	if (__update > 1)
+	  __atomic_impl::notify_all(&_M_counter);
+	else
+	  __atomic_impl::notify_one(&_M_counter);
+      }
+
+    private:
+      alignas(__alignof__(_Tp)) _Tp _M_counter;
+    };
+
+// Note: the _GLIBCXX_REQUIRE_POSIX_SEMAPHORE macro can be used to force the
+// use of Posix semaphores (sem_t). Doing so however, alters the ABI.
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+  // Use futex if available and didn't force use of POSIX
+  using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
+#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  using __fast_semaphore = __platform_semaphore;
+#else
+  using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
+#endif
+
+template<ptrdiff_t __least_max_value>
+  using __semaphore_impl = conditional_t<
+		(__least_max_value > 1),
+		conditional_t<
+		    (__least_max_value <= __fast_semaphore::_S_max),
+		    __fast_semaphore,
+		    __atomic_semaphore<ptrdiff_t>>,
+		__fast_semaphore>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 1a304261fe7..5afe33b41d9 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -163,6 +163,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     compare_exchange_strong(bool& __i1, bool __i2,
 		    memory_order __m = memory_order_seq_cst) volatile noexcept
     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const
+      noexcept
+    { _M_base.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_base.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_base.notify_all(); }
+#endif
   };
 
 #if __cplusplus <= 201703L
@@ -363,6 +377,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     memory_order __m = memory_order_seq_cst) volatile noexcept
       { return compare_exchange_strong(__e, __i, __m,
                                        __cmpexch_failure_order(__m)); }
+
+#if __cplusplus > 201703L
+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+			 [__m, this, __old]
+			 {
+			   const auto __v = this->load(__m);
+			   // TODO make this ignore padding bits when we
+			   // can do that
+			   return __builtin_memcmp(&__old, &__v,
+						    sizeof(_Tp)) != 0;
+			 });
+    }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    void notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -601,6 +639,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					    __cmpexch_failure_order(__m));
       }
 
+#if __cplusplus > 201703L
+    void wait(__pointer_type __old,
+	      memory_order __m = memory_order_seq_cst) noexcept
+    { _M_b.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_b.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_b.notify_all(); }
+#endif
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
@@ -1353,6 +1404,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 						     memory_order_seq_cst);
     }
 
+
+#if __cplusplus > 201703L
+  template<typename _Tp>
+    inline void
+    atomic_wait(const atomic<_Tp>* __a,
+	        typename std::atomic<_Tp>::value_type __old) noexcept
+    { __a->wait(__old); }
+
+  template<typename _Tp>
+    inline void
+    atomic_wait_explicit(const atomic<_Tp>* __a,
+			 typename std::atomic<_Tp>::value_type __old,
+			 std::memory_order __m) noexcept
+    { __a->wait(__old, __m); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_one(atomic<_Tp>* __a) noexcept
+    { __a->notify_one(); }
+
+  template<typename _Tp>
+    inline void
+    atomic_notify_all(atomic<_Tp>* __a) noexcept
+    { __a->notify_all(); }
+
+#endif // C++2a
+
   // Function templates for atomic_integral and atomic_pointer operations only.
   // Some operations (and, or, xor) are only available for atomic integrals,
   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
new file mode 100644
index 00000000000..9d9c880a88b
--- /dev/null
+++ b/libstdc++-v3/include/std/latch
@@ -0,0 +1,91 @@
+// <latch> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/latch
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_LATCH
+#define _GLIBCXX_LATCH
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_latch 201907L
+
+#include <bits/atomic_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  class latch
+  {
+  public:
+    static constexpr ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__int_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) noexcept
+      : _M_a(__expected) { }
+
+    ~latch() = default;
+    latch(const latch&) = delete;
+    latch& operator=(const latch&) = delete;
+
+    _GLIBCXX_ALWAYS_INLINE void
+    count_down(ptrdiff_t __update = 1)
+    {
+      auto const __old = __atomic_impl::fetch_sub(&_M_a,
+				    __update, memory_order::release);
+      if (__old == __update)
+	__atomic_impl::notify_all(&_M_a);
+    }
+
+    _GLIBCXX_ALWAYS_INLINE bool
+    try_wait() const noexcept
+    { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait() const noexcept
+    {
+      auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
+      std::__atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
+    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    arrive_and_wait(ptrdiff_t __update = 1) noexcept
+    {
+      count_down(__update);
+      wait();
+    }
+
+  private:
+    alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
+  };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_LATCH
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..b4facde4ea1
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,92 @@
+// <semaphore> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/semaphore
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SEMAPHORE
+#define _GLIBCXX_SEMAPHORE
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+#include <bits/semaphore_base.h>
+#include <ext/numeric_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<ptrdiff_t __least_max_value =
+			__gnu_cxx::__int_traits<ptrdiff_t>::__max>
+    class counting_semaphore
+    {
+      static_assert(__least_max_value >= 0);
+
+      __semaphore_impl<__least_max_value> _M_sem;
+
+    public:
+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
+	: _M_sem(__desired)
+      { }
+
+      ~counting_semaphore() = default;
+
+      counting_semaphore(const counting_semaphore&) = delete;
+      counting_semaphore& operator=(const counting_semaphore&) = delete;
+
+      static constexpr ptrdiff_t
+      max() noexcept
+      { return __least_max_value; }
+
+      void
+      release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
+      { _M_sem._M_release(__update); }
+
+      void
+      acquire() noexcept(noexcept(_M_sem._M_acquire()))
+      { _M_sem._M_acquire(); }
+
+      bool
+      try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
+      { return _M_sem._M_try_acquire(); }
+
+      template<typename _Rep, typename _Period>
+	bool
+	try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
+	{ return _M_sem._M_try_acquire_for(__rtime); }
+
+      template<typename _Clock, typename _Dur>
+	bool
+	try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
+	{ return _M_sem._M_try_acquire_until(__atime); }
+    };
+
+ using binary_semaphore = std::counting_semaphore<1>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // __cplusplus > 201703L
+#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index ebb50a04d24..dcfbbb9ee54 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -216,6 +216,7 @@
 #ifdef _GLIBCXX_HAS_GTHREADS
 # define __cpp_lib_jthread 201911L
 #endif
+#define __cpp_lib_latch 201907L
 #define __cpp_lib_list_remove_return_type 201806L
 #if __cpp_lib_concepts
 # define __cpp_lib_make_obj_using_allocator 201811L
@@ -225,6 +226,7 @@
 #if __cpp_lib_concepts
 # define __cpp_lib_ranges 201911L
 #endif
+#define __cpp_lib_semaphore 201907L
 #define __cpp_lib_shift 201806L
 #define __cpp_lib_span 202002L
 #define __cpp_lib_ssize 201902L
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
new file mode 100644
index 00000000000..5f1e30a710f
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<bool> a(false);
+  std::atomic<bool> b(false);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+		  if (a.load())
+		    {
+		      b.store(true);
+		    }
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(true);
+  a.notify_one();
+  t.join();
+  VERIFY( b.load() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
new file mode 100644
index 00000000000..0249341055c
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -0,0 +1,31 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "atomic/wait_notify_util.h"
+
+int
+main ()
+{
+  struct S{ int i; };
+  check<S> check_s{S{0},S{42}};
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
new file mode 100644
index 00000000000..8531bb2e788
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <type_traits>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+int
+main ()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  long aa;
+  long bb;
+
+  std::atomic<long*> a(nullptr);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(nullptr);
+		  if (a.load() == &aa)
+		    a.store(&bb);
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(&aa);
+  a.notify_one();
+  t.join();
+  VERIFY( a.load() == &bb);
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
new file mode 100644
index 00000000000..4f026e1dc9c
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic_flag a;
+  std::atomic_flag b;
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(false);
+		  b.test_and_set();
+		  b.notify_one();
+		});
+
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.test_and_set();
+  a.notify_one();
+  b.wait(false);
+  t.join();
+
+  VERIFY( a.test() );
+  VERIFY( b.test() );
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
new file mode 100644
index 00000000000..b46eb603304
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "atomic/wait_notify_util.h"
+
+int
+main ()
+{
+  check<float> f;
+  check<double> d;
+  check<long double> l;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
new file mode 100644
index 00000000000..6e9ee7dbf93
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -0,0 +1,65 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "atomic/wait_notify_util.h"
+
+void
+test01()
+{
+  struct S{ int i; };
+  std::atomic<S> s;
+
+  s.wait(S{42});
+}
+
+int
+main ()
+{
+  // check<bool> bb;
+  check<char> ch;
+  check<signed char> sch;
+  check<unsigned char> uch;
+  check<short> s;
+  check<unsigned short> us;
+  check<int> i;
+  check<unsigned int> ui;
+  check<long> l;
+  check<unsigned long> ul;
+  check<long long> ll;
+  check<unsigned long long> ull;
+
+  check<wchar_t> wch;
+  check<char8_t> ch8;
+  check<char16_t> ch16;
+  check<char32_t> ch32;
+
+  check<int8_t> i8;
+  check<int16_t> i16;
+  check<int32_t> i32;
+  check<int64_t> i64;
+
+  check<uint8_t> u8;
+  check<uint16_t> u16;
+  check<uint32_t> u32;
+  check<uint64_t> u64;
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
new file mode 100644
index 00000000000..1ced9d44b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -0,0 +1,103 @@
+// { dg-options "-std=gnu++2a -pthread -latomic -L../../libatomic/.libs" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  Tp aa = val1;
+  std::atomic_ref<Tp> a(aa);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp,
+	 bool = std::is_integral_v<Tp>
+	 || std::is_floating_point_v<Tp>>
+struct check;
+
+template<typename Tp>
+struct check<Tp, true>
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+template<typename Tp>
+struct check<Tp, false>
+{
+  check(Tp b)
+  {
+    Tp a;
+    VERIFY(check_wait_notify(a, b) == b);
+  }
+};
+
+struct foo
+{
+  long a = 0;
+  long b = 0;
+
+  foo& operator=(foo const&) = default;
+
+  friend bool
+  operator==(foo const& rhs, foo const& lhs)
+  { return rhs.a == lhs.a && rhs.b == lhs.b; }
+};
+
+int
+main ()
+{
+  check<long>();
+  check<double>();
+  check<foo>({42, 48});
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
new file mode 100644
index 00000000000..aa203cdf525
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <latch>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <latch>"
+#elif __cpp_lib_latch!= 201907L
+# error "Feature-test macro for latch has wrong value in <latch>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
new file mode 100644
index 00000000000..318a859ee21
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_latch
+# error "Feature-test macro for latch missing in <version>"
+#elif __cpp_lib_latch != 201907L
+# error "Feature-test macro for latch has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
new file mode 100644
index 00000000000..5d08000f430
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+//
+#include <latch>
+#include <atomic>
+#include <thread>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::latch l(3);
+
+  VERIFY( !l.try_wait() );
+
+  auto fn = [&]
+  {
+    l.count_down();
+  };
+
+  std::thread t0(fn);
+  std::thread t1(fn);
+
+  l.arrive_and_wait();
+  t0.join();
+  t1.join();
+
+  VERIFY( l.try_wait() );
+}
+
+void
+test02()
+{
+  std::latch l(3);
+  std::thread t([&]
+    {
+      l.count_down();
+    });
+
+  l.arrive_and_wait(2);
+  t.join();
+  VERIFY( l.try_wait() );
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..98743f5e27c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
new file mode 100644
index 00000000000..d74cfad53e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::counting_semaphore<-1> sem(2);
+  return 0;
+}
+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
new file mode 100644
index 00000000000..25280441d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <limits>
+#include <cstddef>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  std::counting_semaphore<10> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+void test02()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
new file mode 100644
index 00000000000..3f450e74661
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s.try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
new file mode 100644
index 00000000000..13bd7487d56
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_for(dur) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    VERIFY( !s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+
+    a.wait(1);
+    VERIFY( s._M_try_acquire_for(dur) );
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+void test03()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(2);
+  s._M_acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s._M_try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test04()
+{
+  using namespace std::chrono_literals;
+  std::__platform_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s._M_try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s._M_try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s._M_acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s._M_release(1);
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+#endif
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
new file mode 100644
index 00000000000..af7ab7bac39
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
new file mode 100644
index 00000000000..a319e8b60a6
--- /dev/null
+++ b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
@@ -0,0 +1,160 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <concepts>
+#include <mutex>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  a.wait(val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  a.notify_one();
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+  requires std::equality_comparable<Tp>
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  if (a.load() != val2)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+  using namespace std::literals::chrono_literals;
+
+  std::mutex m;
+  std::condition_variable cv;
+
+  std::atomic<Tp> a(val1);
+  std::thread t([&]
+		{
+		  cv.notify_one();
+		  std::atomic_wait(&a, val1);
+		  auto v = a.load();
+		  // TODO this needs to zero padding bits when we can do that
+		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
+		    a = val1;
+		});
+  std::unique_lock<std::mutex> l(m);
+  cv.wait(l);
+  std::this_thread::sleep_for(100ms);
+  a.store(val2);
+  std::atomic_notify_one(&a);
+  t.join();
+  return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+  check(Tp a = 0, Tp b = 42)
+  {
+    if constexpr (std::equality_comparable<Tp>)
+    {
+      VERIFY( check_wait_notify(a, b) == b);
+      VERIFY( check_atomic_wait_notify(a, b) == b);
+    }
+    else
+    {
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
+      }
+
+      {
+	// TODO this needs to zero padding bits when we can do that
+	auto v = check_atomic_wait_notify(a, b);
+	VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
+      }
+    }
+  }
+};
-- 
2.26.2



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-10-26 21:48                           ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
@ 2020-10-27 10:23                             ` Jonathan Wakely
  2020-11-20 22:44                               ` Thomas Rodgers
  2020-11-21 15:16                             ` Andreas Schwab
  1 sibling, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-10-27 10:23 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

On 26/10/20 14:48 -0700, Thomas Rodgers wrote:
>+#include <ext/numeric_traits.h>
>+
>+#if __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>

It occurs to me now that this check probably isn't robust enough. For
any POSIX system it's probably safe to assume that <semaphore.h> means
the POSIX header and so sem_t is available.

But on non-POSIX systems there could be some other, unrelated header
called <semaphore.h> in the include paths that the user is compiling
this header with. It's not inconceivable that the user's own project
or some third party lib could provide a file called semaphore.h, which
wouldn't define sem_t, sem_init etc.

It's OK for now, but we should revisit this and add an autoconf check
for sem_init etc. to check at build time whether we've got POSIX
semaphores available or not.

Please add a "FIXME: replace this with an autoconf check" comment
here.

OK for trunk with that change, thanks.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-10-27 10:23                             ` Jonathan Wakely
@ 2020-11-20 22:44                               ` Thomas Rodgers
  2020-11-22 21:13                                 ` Stephan Bergmann
  2020-11-22 21:41                                 ` Stephan Bergmann
  0 siblings, 2 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-11-20 22:44 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches List, libstdc++, trodgers

Tested x86_64-pc-linux-gnu, committed.

> On Oct 27, 2020, at 3:23 AM, Jonathan Wakely <jwakely@redhat.com> wrote:
> 
> On 26/10/20 14:48 -0700, Thomas Rodgers wrote:
>> +#include <ext/numeric_traits.h>
>> +
>> +#if __has_include(<semaphore.h>)
>> +#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>> +#include <semaphore.h>
> 
> It occurs to me now that this check probably isn't robust enough. For
> any POSIX system it's probably safe to assume that <semaphore.h> means
> the POSIX header and so sem_t is available.
> 
> But on non-POSIX systems there could be some other, unrelated header
> called <semaphore.h> in the include paths that the user is compiling
> this header with. It's not inconceivable that the user's own project
> or some third party lib could provide a file called semaphore.h, which
> wouldn't define sem_t, sem_init etc.
> 
> It's OK for now, but we should revisit this and add an autoconf check
> for sem_init etc. to check at build time whether we've got POSIX
> semaphores available or not.
> 
> Please add a "FIXME: replace this with an autoconf check" comment
> here.
> 
> OK for trunk with that change, thanks.
> 


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-10-26 21:48                           ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
  2020-10-27 10:23                             ` Jonathan Wakely
@ 2020-11-21 15:16                             ` Andreas Schwab
  2020-11-21 17:04                               ` Jonathan Wakely
  1 sibling, 1 reply; 43+ messages in thread
From: Andreas Schwab @ 2020-11-21 15:16 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: gcc-patches, libstdc++, trodgers

In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
                 from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
                 from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
                 from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-21 15:16                             ` Andreas Schwab
@ 2020-11-21 17:04                               ` Jonathan Wakely
  2020-11-21 17:39                                 ` Jonathan Wakely
  0 siblings, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-21 17:04 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2902 bytes --]

On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>                 from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>                 from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>                 from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>                 from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')

I'm testing this.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 6587 bytes --]

commit 613ac97bed57eb0edb1803b66d5ce3510e665b3d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Sat Nov 21 16:52:22 2020

    libstdc++: Fix atomic waiting for non-linux targets
    
    This fixes some UNRESOLVED tests on (at least) Solaris and Darwin, and
    disables some tests that hang forever on Solaris. A proper fix is still
    needed.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/atomic_base.h (atomic_flag::wait): Use correct
            type for __atomic_wait call.
            * include/bits/atomic_timed_wait.h (__atomic_wait_until): Check
            _GLIBCXX_HAVE_LINUX_FUTEX.
            * include/bits/atomic_wait.h (__atomic_notify): Likewise.
            * include/bits/semaphore_base.h (_GLIBCXX_HAVE_POSIX_SEMAPHORE):
            Only define if SEM_VALUE_MAX or _POSIX_SEM_VALUE_MAX is defined.
            * testsuite/29_atomics/atomic/wait_notify/bool.cc: Disable on
            non-linux targes.
            * testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
            * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
            * testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise.

diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index dd4db926592e..7de02f169977 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -234,7 +234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     wait(bool __old,
 	memory_order __m = memory_order_seq_cst) const noexcept
     {
-      std::__atomic_wait(&_M_i, __old,
+      std::__atomic_wait(&_M_i, static_cast<__atomic_flag_data_type>(__old),
 			 [__m, this, __old]()
 			 { return this->test(__m) != __old; });
     }
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 7712a6c591dc..405f7e93ca85 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -240,12 +240,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       do
 	{
 	  __atomic_wait_status __res;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
 	  if constexpr (__platform_wait_uses_type<_Tp>)
 	    {
 	      __res = __detail::__platform_wait_until((__platform_wait_t*)(void*) __addr,
 						      __old, __atime);
 	    }
 	  else
+#endif
 	    {
 	      __res = __w._M_do_wait_until(__version, __atime);
 	    }
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 2d08e5325fb2..7b2682a577ef 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -292,11 +292,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (!__w._M_waiting())
 	return;
 
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
       if constexpr (__platform_wait_uses_type<_Tp>)
 	{
 	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
 	}
       else
+#endif
 	{
 	  __w._M_notify(__all);
 	}
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index da6dc4b91858..78a0b6ba26e6 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -39,8 +39,10 @@
 #include <ext/numeric_traits.h>
 
 #if __has_include(<semaphore.h>)
-#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
-#include <semaphore.h>
+# include <semaphore.h>
+# if defined SEM_VALUE_MAX || _POSIX_SEM_VALUE_MAX
+#  define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+# endif
 #endif
 
 #include <chrono>
@@ -54,7 +56,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   struct __platform_semaphore
   {
     using __clock_t = chrono::system_clock;
+#ifdef SEM_VALUE_MAX
     static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+#else
+    static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
+#endif
 
     explicit __platform_semaphore(ptrdiff_t __count) noexcept
     {
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index 5f1e30a710fe..29781c6e1357 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index 8531bb2e7880..f54961f893d4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
+// { dg-additional-options "-pthread" { target pthread } }
 // { dg-require-gthreads "" }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 4f026e1dc9c1..763d3e77159c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 640a84e0342e..27d9b601c2f4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-21 17:04                               ` Jonathan Wakely
@ 2020-11-21 17:39                                 ` Jonathan Wakely
  2020-11-22  0:36                                   ` H.J. Lu
  2020-11-23 16:08                                   ` Jonathan Wakely
  0 siblings, 2 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-21 17:39 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3281 bytes --]

On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>
>I'm testing this.

I'm committing this instead, it's the same but also disables
29_atomics/atomic/wait_notify/generic.cc on non-linux targets.

Tested sparc-solaris2.11 and powerpc64le-linux.

There are still some timeouts on linux:

FAIL: 30_threads/latch/3.cc execution test
FAIL: 30_threads/semaphore/try_acquire_for.cc execution test



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 7354 bytes --]

commit 6f5387b7c9047baa5ee1385c8f5148d2c351bd20
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Sat Nov 21 16:52:22 2020

    libstdc++: Fix atomic waiting for non-linux targets
    
    This fixes some UNRESOLVED tests on (at least) Solaris and Darwin, and
    disables some tests that hang forever on Solaris. A proper fix is still
    needed.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/atomic_base.h (atomic_flag::wait): Use correct
            type for __atomic_wait call.
            * include/bits/atomic_timed_wait.h (__atomic_wait_until): Check
            _GLIBCXX_HAVE_LINUX_FUTEX.
            * include/bits/atomic_wait.h (__atomic_notify): Likewise.
            * include/bits/semaphore_base.h (_GLIBCXX_HAVE_POSIX_SEMAPHORE):
            Only define if SEM_VALUE_MAX or _POSIX_SEM_VALUE_MAX is defined.
            * testsuite/29_atomics/atomic/wait_notify/bool.cc: Disable on
            non-linux targes.
            * testsuite/29_atomics/atomic/wait_notify/generic.cc: Likewise.
            * testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
            * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
            * testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise.

diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index dd4db926592e..7de02f169977 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -234,7 +234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     wait(bool __old,
 	memory_order __m = memory_order_seq_cst) const noexcept
     {
-      std::__atomic_wait(&_M_i, __old,
+      std::__atomic_wait(&_M_i, static_cast<__atomic_flag_data_type>(__old),
 			 [__m, this, __old]()
 			 { return this->test(__m) != __old; });
     }
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 7712a6c591dc..405f7e93ca85 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -240,12 +240,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       do
 	{
 	  __atomic_wait_status __res;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
 	  if constexpr (__platform_wait_uses_type<_Tp>)
 	    {
 	      __res = __detail::__platform_wait_until((__platform_wait_t*)(void*) __addr,
 						      __old, __atime);
 	    }
 	  else
+#endif
 	    {
 	      __res = __w._M_do_wait_until(__version, __atime);
 	    }
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 2d08e5325fb2..7b2682a577ef 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -292,11 +292,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (!__w._M_waiting())
 	return;
 
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
       if constexpr (__platform_wait_uses_type<_Tp>)
 	{
 	  __platform_notify((__platform_wait_t*)(void*) __addr, __all);
 	}
       else
+#endif
 	{
 	  __w._M_notify(__all);
 	}
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index da6dc4b91858..78a0b6ba26e6 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -39,8 +39,10 @@
 #include <ext/numeric_traits.h>
 
 #if __has_include(<semaphore.h>)
-#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
-#include <semaphore.h>
+# include <semaphore.h>
+# if defined SEM_VALUE_MAX || _POSIX_SEM_VALUE_MAX
+#  define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+# endif
 #endif
 
 #include <chrono>
@@ -54,7 +56,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   struct __platform_semaphore
   {
     using __clock_t = chrono::system_clock;
+#ifdef SEM_VALUE_MAX
     static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
+#else
+    static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
+#endif
 
     explicit __platform_semaphore(ptrdiff_t __count) noexcept
     {
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index 5f1e30a710fe..29781c6e1357 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
index 0249341055cc..629556a9d2d0 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index 8531bb2e7880..f54961f893d4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
+// { dg-additional-options "-pthread" { target pthread } }
 // { dg-require-gthreads "" }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 4f026e1dc9c1..763d3e77159c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 640a84e0342e..27d9b601c2f4 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -1,7 +1,8 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-21 17:39                                 ` Jonathan Wakely
@ 2020-11-22  0:36                                   ` H.J. Lu
  2020-11-23 14:50                                     ` Jonathan Wakely
  2020-11-24 23:45                                     ` Jonathan Wakely
  2020-11-23 16:08                                   ` Jonathan Wakely
  1 sibling, 2 replies; 43+ messages in thread
From: H.J. Lu @ 2020-11-22  0:36 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
> >On 21/11/20 16:16 +0100, Andreas Schwab wrote:
> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
> >
> >I'm testing this.
>
> I'm committing this instead, it's the same but also disables
> 29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>
> Tested sparc-solaris2.11 and powerpc64le-linux.
>
> There are still some timeouts on linux:
>
> FAIL: 30_threads/latch/3.cc execution test
> FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>

I opened:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936

-- 
H.J.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-20 22:44                               ` Thomas Rodgers
@ 2020-11-22 21:13                                 ` Stephan Bergmann
  2020-11-23 18:33                                   ` Jonathan Wakely
  2020-11-22 21:41                                 ` Stephan Bergmann
  1 sibling, 1 reply; 43+ messages in thread
From: Stephan Bergmann @ 2020-11-22 21:13 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: trodgers, libstdc++, gcc-patches List, Jonathan Wakely

On 20/11/2020 23:44, Thomas Rodgers wrote:
> Tested x86_64-pc-linux-gnu, committed.

Clang complains:

> $ cat test.cc
> #include <semaphore>
> 
> $ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++20 -fsyntax-only test.cc
> In file included from test.cc:1:
> In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/semaphore:36:
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/semaphore_base.h:145:22: error: no viable conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::__platform_semaphore::__clock_t' (aka 'const std::chrono::system_clock')
>             const __clock_t __s_entry = __clock_t::now();
>                             ^           ~~~~~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::chrono::system_clock &' for 1st argument
>     struct system_clock
>            ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'std::chrono::system_clock &&' for 1st argument
> 1 error generated.

which

> diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
> index 78a0b6ba26e..f25c9fdb325 100644
> --- a/libstdc++-v3/include/bits/semaphore_base.h
> +++ b/libstdc++-v3/include/bits/semaphore_base.h
> @@ -142,7 +142,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         else
>           {
>             const typename _Clock::time_point __c_entry = _Clock::now();
> -           const __clock_t __s_entry = __clock_t::now();
> +           const __clock_t::time_point __s_entry = __clock_t::now();
>             const auto __delta = __atime - __c_entry;
>             const auto __s_atime = __s_entry + __delta;
>             if (_M_try_acquire_until_impl(__s_atime))
> ~

would fix.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-20 22:44                               ` Thomas Rodgers
  2020-11-22 21:13                                 ` Stephan Bergmann
@ 2020-11-22 21:41                                 ` Stephan Bergmann
  2020-11-23 18:32                                   ` Jonathan Wakely
  1 sibling, 1 reply; 43+ messages in thread
From: Stephan Bergmann @ 2020-11-22 21:41 UTC (permalink / raw)
  To: Thomas Rodgers; +Cc: trodgers, libstdc++, gcc-patches List, Jonathan Wakely

On 20/11/2020 23:44, Thomas Rodgers wrote:
> Tested x86_64-pc-linux-gnu, committed.

...and there are multiple definition complaints from the linker because 
of two missing "include":

> index 7b2682a577e..23ab2018ca8 100644
> --- a/libstdc++-v3/include/bits/atomic_wait.h
> +++ b/libstdc++-v3/include/bits/atomic_wait.h
> @@ -223,7 +223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        { _M_w._M_do_wait(_M_version); }
>      };
>  
> -    void
> +    inline void
>      __thread_relax() noexcept
>      {
>  #if defined __i386__ || defined __x86_64__
> @@ -233,7 +233,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  #endif
>      }
>  
> -    void
> +    inline void
>      __thread_yield() noexcept
>     {
>  #if defined _GLIBCXX_USE_SCHED_YIELD


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-22  0:36                                   ` H.J. Lu
@ 2020-11-23 14:50                                     ` Jonathan Wakely
  2020-11-24 23:45                                     ` Jonathan Wakely
  1 sibling, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-23 14:50 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

On 21/11/20 16:36 -0800, H.J. Lu wrote:
>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
><gcc-patches@gcc.gnu.org> wrote:
>>
>> On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>> >On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>> >
>> >I'm testing this.
>>
>> I'm committing this instead, it's the same but also disables
>> 29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>
>> Tested sparc-solaris2.11 and powerpc64le-linux.
>>
>> There are still some timeouts on linux:
>>
>> FAIL: 30_threads/latch/3.cc execution test
>> FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>
>
>I opened:
>
>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936

Thanks.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-21 17:39                                 ` Jonathan Wakely
  2020-11-22  0:36                                   ` H.J. Lu
@ 2020-11-23 16:08                                   ` Jonathan Wakely
  1 sibling, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-23 16:08 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3424 bytes --]

On 21/11/20 17:39 +0000, Jonathan Wakely wrote:
>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>               from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>               from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>               from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>
>>I'm testing this.
>
>I'm committing this instead, it's the same but also disables
>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>
>Tested sparc-solaris2.11 and powerpc64le-linux.
>
>There are still some timeouts on linux:
>
>FAIL: 30_threads/latch/3.cc execution test
>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test


Here's another small fix.

Tested powerpc64le-linux, pushed to trunk.




[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 2174 bytes --]

commit fd62daea40e09c1e6d599a6171db6b298d6c362e
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Nov 23 15:46:24 2020

    libstdc++: Link tests to libatomic as required [PR 97948]
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/97948
            * testsuite/29_atomics/atomic_float/wait_notify.cc: Add options
            for libatomic.
            * testsuite/29_atomics/atomic_integral/wait_notify.cc: Likewise.
            * testsuite/29_atomics/atomic_ref/wait_notify.cc: Likewise.

diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 27d9b601c2f4..8f9e4a39a21f 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -2,6 +2,7 @@
 // { dg-do run { target c++2a } }
 // { dg-require-gthreads "" }
 // { dg-additional-options "-pthread" { target pthread } }
+// { dg-add-options libatomic }
 // { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index 6e9ee7dbf93f..abf2bfdbee96 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -2,6 +2,7 @@
 // { dg-do run { target c++2a } }
 // { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-add-options libatomic }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
index dc5ae7a21eac..b38fc206d468 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -2,6 +2,7 @@
 // { dg-do run { target c++2a } }
 // { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-add-options libatomic }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-22 21:41                                 ` Stephan Bergmann
@ 2020-11-23 18:32                                   ` Jonathan Wakely
  0 siblings, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:32 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 809 bytes --]

On 22/11/20 22:41 +0100, Stephan Bergmann wrote:
>On 20/11/2020 23:44, Thomas Rodgers wrote:
>>Tested x86_64-pc-linux-gnu, committed.
>
>...and there are multiple definition complaints from the linker 
>because of two missing "include":
>
>>index 7b2682a577e..23ab2018ca8 100644
>>--- a/libstdc++-v3/include/bits/atomic_wait.h
>>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>>@@ -223,7 +223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       { _M_w._M_do_wait(_M_version); }
>>     };
>>-    void
>>+    inline void
>>     __thread_relax() noexcept
>>     {
>> #if defined __i386__ || defined __x86_64__
>>@@ -233,7 +233,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> #endif
>>     }
>>-    void
>>+    inline void
>>     __thread_yield() noexcept
>>    {
>> #if defined _GLIBCXX_USE_SCHED_YIELD

Committed, thanks.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 986 bytes --]

commit 0986d3bc621b12c3d0367bf7bd25927c7fbfc552
Author: Stephan Bergmann <sbergman@redhat.com>
Date:   Mon Nov 23 18:14:44 2020

    libstdc++: Fix linker errors due to missing 'inline' keywords
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/atomic_wait.h (__thread_relax, __thread_yield):
            Add 'inline'.

diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index a40cff124d7d..cd756f68de6d 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { _M_w._M_do_wait(_M_version); }
     };
 
-    void
+    inline void
     __thread_relax() noexcept
     {
 #if defined __i386__ || defined __x86_64__
@@ -234,9 +234,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
     }
 
-    void
+    inline void
     __thread_yield() noexcept
-   {
+    {
 #if defined _GLIBCXX_USE_SCHED_YIELD
      __gthread_yield();
 #endif

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-22 21:13                                 ` Stephan Bergmann
@ 2020-11-23 18:33                                   ` Jonathan Wakely
  0 siblings, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-23 18:33 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: Thomas Rodgers, trodgers, libstdc++, gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 2583 bytes --]

On 22/11/20 22:13 +0100, Stephan Bergmann wrote:
>On 20/11/2020 23:44, Thomas Rodgers wrote:
>>Tested x86_64-pc-linux-gnu, committed.
>
>Clang complains:
>
>>$ cat test.cc
>>#include <semaphore>
>>
>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++20 -fsyntax-only test.cc
>>In file included from test.cc:1:
>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/semaphore:36:
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/semaphore_base.h:145:22: error: no viable conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::__platform_semaphore::__clock_t' (aka 'const std::chrono::system_clock')
>>            const __clock_t __s_entry = __clock_t::now();
>>                            ^           ~~~~~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'const std::chrono::system_clock &' for 1st argument
>>    struct system_clock
>>           ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/chrono:1101:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') to 'std::chrono::system_clock &&' for 1st argument
>>1 error generated.
>
>which
>
>>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>>index 78a0b6ba26e..f25c9fdb325 100644
>>--- a/libstdc++-v3/include/bits/semaphore_base.h
>>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>>@@ -142,7 +142,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        else
>>          {
>>            const typename _Clock::time_point __c_entry = _Clock::now();
>>-           const __clock_t __s_entry = __clock_t::now();
>>+           const __clock_t::time_point __s_entry = __clock_t::now();
>>            const auto __delta = __atime - __c_entry;
>>            const auto __s_atime = __s_entry + __delta;
>>            if (_M_try_acquire_until_impl(__s_atime))
>>~
>
>would fix.

I just used 'auto'` instead.

Committed, thanks.

The fact this didn't error with GCC suggests we're missing some tests.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 972 bytes --]

commit 1ccee0fbfa8e528b3671dfbf4dad5b6f67755e4c
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Nov 23 18:16:44 2020

    libstdc++: Fix variable declared with wrong type
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/semaphore_base.h
            (__platform_semaphore::_M_try_acquire_until): Fix type of
            variable.

diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index 0692f95f24f2..56333bbbfef7 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -141,7 +141,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	else
 	  {
 	    const typename _Clock::time_point __c_entry = _Clock::now();
-	    const __clock_t __s_entry = __clock_t::now();
+	    const auto __s_entry = __clock_t::now();
 	    const auto __delta = __atime - __c_entry;
 	    const auto __s_atime = __s_entry + __delta;
 	    if (_M_try_acquire_until_impl(__s_atime))

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-22  0:36                                   ` H.J. Lu
  2020-11-23 14:50                                     ` Jonathan Wakely
@ 2020-11-24 23:45                                     ` Jonathan Wakely
  2020-11-25  1:07                                       ` Jonathan Wakely
  1 sibling, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-24 23:45 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 3718 bytes --]

On 21/11/20 16:36 -0800, H.J. Lu wrote:
>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
><gcc-patches@gcc.gnu.org> wrote:
>>
>> On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>> >On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>> >>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>> >>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>> >>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>> >>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>> >
>> >I'm testing this.
>>
>> I'm committing this instead, it's the same but also disables
>> 29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>
>> Tested sparc-solaris2.11 and powerpc64le-linux.
>>
>> There are still some timeouts on linux:
>>
>> FAIL: 30_threads/latch/3.cc execution test
>> FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>
>
>I opened:
>
>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936

I've disabled the failing tests for now. They can be re-enabled after
the problem is found and fixed.

Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 3503 bytes --]

commit a3313a2214a6253672ab4fa37a2dcf57fd0f8dce
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Nov 24 23:22:01 2020

    libstdc++: Disable failing tests [PR 97936]
    
    These tests are unstable and causing failures due to timeouts. Disable
    them until the cause can be found, so that testing doesn't have to wait
    for them to timeout.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/97936
            PR libstdc++/97944
            * testsuite/29_atomics/atomic_integral/wait_notify.cc: Disable.
            Do not require pthreads, but add -pthread when appropriate.
            * testsuite/30_threads/jthread/95989.cc: Likewise.
            * testsuite/30_threads/latch/3.cc: Likewise.
            * testsuite/30_threads/semaphore/try_acquire_until.cc: Likewise.

diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index abf2bfdbee96..762583cf8c76 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -1,8 +1,9 @@
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
 // { dg-add-options libatomic }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { *-*-* } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/30_threads/jthread/95989.cc b/libstdc++-v3/testsuite/30_threads/jthread/95989.cc
index c7a9430eee90..a179eab38198 100644
--- a/libstdc++-v3/testsuite/30_threads/jthread/95989.cc
+++ b/libstdc++-v3/testsuite/30_threads/jthread/95989.cc
@@ -20,6 +20,7 @@
 // { dg-require-gthreads {} }
 // { dg-additional-options "-pthread" { target pthread } }
 // { dg-additional-options "-static" { target static } }
+// { dg-skip-if "broken" { *-*-* } }
 
 #include <thread>
 
diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
index 5d08000f4302..6304135a877c 100644
--- a/libstdc++-v3/testsuite/30_threads/latch/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -15,11 +15,12 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
-//
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { *-*-* } }
+
 #include <latch>
 #include <atomic>
 #include <thread>
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
index af7ab7bac395..5e1141425f72 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -15,10 +15,11 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-options "-std=gnu++2a -pthread" }
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
-// { dg-require-effective-target pthread }
 // { dg-require-gthreads "" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-skip-if "broken" { *-*-* } }
 
 #include <semaphore>
 #include <chrono>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-24 23:45                                     ` Jonathan Wakely
@ 2020-11-25  1:07                                       ` Jonathan Wakely
  2020-11-25 10:35                                         ` Jonathan Wakely
  0 siblings, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-25  1:07 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

On 24/11/20 23:45 +0000, Jonathan Wakely wrote:
>On 21/11/20 16:36 -0800, H.J. Lu wrote:
>>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
>><gcc-patches@gcc.gnu.org> wrote:
>>>
>>>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>                from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>                from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>>>
>>>>I'm testing this.
>>>
>>>I'm committing this instead, it's the same but also disables
>>>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>>
>>>Tested sparc-solaris2.11 and powerpc64le-linux.
>>>
>>>There are still some timeouts on linux:
>>>
>>>FAIL: 30_threads/latch/3.cc execution test
>>>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>>
>>
>>I opened:
>>
>>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
>
>I've disabled the failing tests for now. They can be re-enabled after
>the problem is found and fixed.

I was finally able to reproduce the hangs, and I think this is the
fix:

--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -100,9 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
             auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
                                   static_cast<int>(__futex_wait_flags::__wait_private),
                                     __val, nullptr);
-           if (!__e)
+           if (!__e || errno == EAGAIN)
               break;
-           else if (!(errno == EINTR || errno == EAGAIN))
+           else if (errno != EINTR)
               __throw_system_error(__e);
           }
        }

The problem is that we're going into a busy loop when SYS_futex
returns EAGAIN, but that means the current value doesn't match the
expected value, so we should return not keep waiting for the value to
change.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-25  1:07                                       ` Jonathan Wakely
@ 2020-11-25 10:35                                         ` Jonathan Wakely
  2020-11-25 12:32                                           ` Jonathan Wakely
  2020-11-25 18:39                                           ` Jonathan Wakely
  0 siblings, 2 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-25 10:35 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

On 25/11/20 01:07 +0000, Jonathan Wakely wrote:
>On 24/11/20 23:45 +0000, Jonathan Wakely wrote:
>>On 21/11/20 16:36 -0800, H.J. Lu wrote:
>>>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
>>><gcc-patches@gcc.gnu.org> wrote:
>>>>
>>>>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>>>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>               from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>>>>
>>>>>I'm testing this.
>>>>
>>>>I'm committing this instead, it's the same but also disables
>>>>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>>>
>>>>Tested sparc-solaris2.11 and powerpc64le-linux.
>>>>
>>>>There are still some timeouts on linux:
>>>>
>>>>FAIL: 30_threads/latch/3.cc execution test
>>>>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>>>
>>>
>>>I opened:
>>>
>>>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
>>
>>I've disabled the failing tests for now. They can be re-enabled after
>>the problem is found and fixed.
>
>I was finally able to reproduce the hangs, and I think this is the
>fix:
>
>--- a/libstdc++-v3/include/bits/atomic_wait.h
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>@@ -100,9 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>            auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
>                                  static_cast<int>(__futex_wait_flags::__wait_private),
>                                    __val, nullptr);
>-           if (!__e)
>+           if (!__e || errno == EAGAIN)
>              break;
>-           else if (!(errno == EINTR || errno == EAGAIN))
>+           else if (errno != EINTR)
>              __throw_system_error(__e);
>          }
>       }
>
>The problem is that we're going into a busy loop when SYS_futex
>returns EAGAIN, but that means the current value doesn't match the
>expected value, so we should return not keep waiting for the value to
>change.

I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
are still other FAILs to be fixed.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-25 10:35                                         ` Jonathan Wakely
@ 2020-11-25 12:32                                           ` Jonathan Wakely
  2020-11-25 18:39                                           ` Jonathan Wakely
  1 sibling, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-25 12:32 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 5109 bytes --]

On 25/11/20 10:35 +0000, Jonathan Wakely wrote:
>On 25/11/20 01:07 +0000, Jonathan Wakely wrote:
>>On 24/11/20 23:45 +0000, Jonathan Wakely wrote:
>>>On 21/11/20 16:36 -0800, H.J. Lu wrote:
>>>>On Sat, Nov 21, 2020 at 9:40 AM Jonathan Wakely via Gcc-patches
>>>><gcc-patches@gcc.gnu.org> wrote:
>>>>>
>>>>>On 21/11/20 17:04 +0000, Jonathan Wakely wrote:
>>>>>>On 21/11/20 16:16 +0100, Andreas Schwab wrote:
>>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h: In member function 'void std::atomic_flag::wait(bool, std::memory_order) const':
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: error: no matching function for call to '__atomic_wait(const __atomic_flag_data_type*, bool&, std::atomic_flag::wait(bool, std::memory_order) const::<lambda()>)'
>>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:41,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note: candidate: 'template<class _Tp, class _Pred> void std::__atomic_wait(const _Tp*, _Tp, _Pred)'
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_wait.h:265: note:   template argument deduction/substitution failed:
>>>>>>>In file included from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/shared_ptr_atomic.h:33,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/memory:78,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/stdc++.h:82,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/m68k-linux/bits/extc++.h:32,
>>>>>>>              from /daten/aranym/gcc/gcc-20201121/libstdc++-v3/testsuite/17_intro/headers/c++2020/all_attributes.cc:37:
>>>>>>>/daten/aranym/gcc/gcc-20201121/Build/m68k-linux/libstdc++-v3/include/bits/atomic_base.h:239: note:   deduced conflicting types for parameter '_Tp' ('unsigned char' and 'bool')
>>>>>>
>>>>>>I'm testing this.
>>>>>
>>>>>I'm committing this instead, it's the same but also disables
>>>>>29_atomics/atomic/wait_notify/generic.cc on non-linux targets.
>>>>>
>>>>>Tested sparc-solaris2.11 and powerpc64le-linux.
>>>>>
>>>>>There are still some timeouts on linux:
>>>>>
>>>>>FAIL: 30_threads/latch/3.cc execution test
>>>>>FAIL: 30_threads/semaphore/try_acquire_for.cc execution test
>>>>>
>>>>
>>>>I opened:
>>>>
>>>>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97936
>>>
>>>I've disabled the failing tests for now. They can be re-enabled after
>>>the problem is found and fixed.
>>
>>I was finally able to reproduce the hangs, and I think this is the
>>fix:
>>
>>--- a/libstdc++-v3/include/bits/atomic_wait.h
>>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>>@@ -100,9 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
>>                                 static_cast<int>(__futex_wait_flags::__wait_private),
>>                                   __val, nullptr);
>>-           if (!__e)
>>+           if (!__e || errno == EAGAIN)
>>             break;
>>-           else if (!(errno == EINTR || errno == EAGAIN))
>>+           else if (errno != EINTR)
>>             __throw_system_error(__e);
>>         }
>>      }
>>
>>The problem is that we're going into a busy loop when SYS_futex
>>returns EAGAIN, but that means the current value doesn't match the
>>expected value, so we should return not keep waiting for the value to
>>change.
>
>I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
>are still other FAILs to be fixed.

Except that what I pushed was not what I wrote above, as noticed by
Jakub. I need to get more sleep.

Fixed with this patch, pushed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1235 bytes --]

commit a5ccfd04605d940daded7e95474389f1c7dfad61
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Nov 25 12:16:07 2020

    libstdc++: Fix silly typos [PR 97936]
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/97936
            * include/bits/atomic_wait.h (__platform_wait): Check errno,
            not just the value of EAGAIN.
            (__waiters::__waiters()): Fix name of data member.

diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index fdf7c4586f22..5af9367ca2e9 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -100,7 +100,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
 				  static_cast<int>(__futex_wait_flags::__wait_private),
 				    __val, nullptr);
-	    if (!__e || EAGAIN)
+	    if (!__e || errno == EAGAIN)
 	      break;
 	    else if (errno != EINTR)
 	      __throw_system_error(__e);
@@ -133,7 +133,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       mutable __gthread_cond_t _M_cv;
       __waiters() noexcept
       {
-	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cv);
       }
 #  endif
 #endif

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-25 10:35                                         ` Jonathan Wakely
  2020-11-25 12:32                                           ` Jonathan Wakely
@ 2020-11-25 18:39                                           ` Jonathan Wakely
  2020-11-26 16:26                                             ` Jonathan Wakely
  1 sibling, 1 reply; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-25 18:39 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 418 bytes --]

On 25/11/20 10:35 +0000, Jonathan Wakely wrote:
>I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
>are still other FAILs to be fixed.

I think the other FAILs are due to a race condition in the tests,
fixed by this patch. Tested x86_64-linux, powerpc64le-linux,
sparc-solaris2.11 and powerpc-aix. Committed to trunk.

I'll keep an eye on the testresults to see if this really fixes it or
not.




[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 7093 bytes --]

commit f76cad692a62d44ed32d010200bad74f36c73092
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Nov 25 14:39:54 2020

    libstdc++: Fix testsuite helper functions [PR 97936]
    
    This fixes a race condition in the util/atomic/wait_notify_util.h header
    used by several tests, which should make the tests work properly.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/97936
            * testsuite/29_atomics/atomic/wait_notify/bool.cc: Re-eneable
            test.
            * testsuite/29_atomics/atomic/wait_notify/generic.cc: Likewise.
            * testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
            * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
            * testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise.
            * testsuite/29_atomics/atomic_integral/wait_notify.cc: Likewise.
            * testsuite/util/atomic/wait_notify_util.h: Fix missed
            notifications by making the new thread wait until the parent
            thread is waiting on the condition variable.

diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index 29781c6e1357..c14a2391d68b 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -2,7 +2,6 @@
 // { dg-do run { target c++2a } }
 // { dg-require-gthreads "" }
 // { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
index 629556a9d2d0..988fe7b334f3 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.cc
@@ -2,7 +2,6 @@
 // { dg-do run { target c++2a } }
 // { dg-require-gthreads "" }
 // { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index f54961f893d4..87830236e0ee 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -2,7 +2,6 @@
 // { dg-do run { target c++2a } }
 // { dg-additional-options "-pthread" { target pthread } }
 // { dg-require-gthreads "" }
-// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 763d3e77159c..991713fbcdee 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -2,7 +2,6 @@
 // { dg-do run { target c++2a } }
 // { dg-require-gthreads "" }
 // { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
index 8f9e4a39a21f..134eff39e1b1 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/wait_notify.cc
@@ -3,7 +3,6 @@
 // { dg-require-gthreads "" }
 // { dg-additional-options "-pthread" { target pthread } }
 // { dg-add-options libatomic }
-// { dg-skip-if "broken" { ! *-*-*linux } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index 762583cf8c76..c65379cba619 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -3,7 +3,6 @@
 // { dg-require-gthreads "" }
 // { dg-add-options libatomic }
 // { dg-additional-options "-pthread" { target pthread } }
-// { dg-skip-if "broken" { *-*-* } }
 
 // Copyright (C) 2020 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
index a319e8b60a69..f5fff4af4e49 100644
--- a/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
+++ b/libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
@@ -34,16 +34,20 @@ Tp check_wait_notify(Tp val1, Tp val2)
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   std::atomic<Tp> a(val1);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  a.wait(val1);
 		  if (a.load() != val2)
 		    a = val1;
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(val2);
@@ -59,10 +63,15 @@ Tp check_wait_notify(Tp val1, Tp val2)
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   std::atomic<Tp> a(val1);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  a.wait(val1);
 		  auto v = a.load();
@@ -70,7 +79,6 @@ Tp check_wait_notify(Tp val1, Tp val2)
 		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
 		    a = val1;
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(val2);
@@ -87,16 +95,20 @@ Tp check_atomic_wait_notify(Tp val1, Tp val2)
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   std::atomic<Tp> a(val1);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  std::atomic_wait(&a, val1);
 		  if (a.load() != val2)
 		    a = val1;
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(val2);
@@ -112,10 +124,15 @@ Tp check_atomic_wait_notify(Tp val1, Tp val2)
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   std::atomic<Tp> a(val1);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  std::atomic_wait(&a, val1);
 		  auto v = a.load();
@@ -123,7 +140,6 @@ Tp check_atomic_wait_notify(Tp val1, Tp val2)
 		  if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
 		    a = val1;
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(val2);

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] libstdc++: Add C++2a synchronization support
  2020-11-25 18:39                                           ` Jonathan Wakely
@ 2020-11-26 16:26                                             ` Jonathan Wakely
  0 siblings, 0 replies; 43+ messages in thread
From: Jonathan Wakely @ 2020-11-26 16:26 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Andreas Schwab, trodgers, GCC Patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 579 bytes --]

On 25/11/20 18:39 +0000, Jonathan Wakely wrote:
>On 25/11/20 10:35 +0000, Jonathan Wakely wrote:
>>I've pushed that as ad9cbcee543ecccd79fa49dafcd925532d2ce210 but there
>>are still other FAILs to be fixed.
>
>I think the other FAILs are due to a race condition in the tests,
>fixed by this patch. Tested x86_64-linux, powerpc64le-linux,
>sparc-solaris2.11 and powerpc-aix. Committed to trunk.
>
>I'll keep an eye on the testresults to see if this really fixes it or
>not.

This fixes some more races of the same kind, in different tiles.

Tested as above. Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 4212 bytes --]

commit 10522ed1089277e2aa6cd708205aa5c730179cf0
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Nov 26 12:55:47 2020

    libstdc++: Fix some more deadlocks in tests [PR 97936]
    
    The missed notifications fixed in r11-5383 also happen in some other
    tests which have similar code.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/97936
            * testsuite/29_atomics/atomic/wait_notify/bool.cc: Fix missed
            notifications by making the new thread wait until the parent
            thread is waiting on the condition variable.
            * testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise.
            * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise.
            * testsuite/29_atomics/atomic_ref/wait_notify.cc: Likewise.

diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
index c14a2391d68b..1fc014911737 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -36,11 +36,16 @@ main ()
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   std::atomic<bool> a(false);
   std::atomic<bool> b(false);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  a.wait(false);
 		  if (a.load())
@@ -48,7 +53,6 @@ main ()
 		      b.store(true);
 		    }
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(true);
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
index 87830236e0ee..3b699e9133b2 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
@@ -36,6 +36,7 @@ main ()
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   long aa;
   long bb;
@@ -43,12 +44,15 @@ main ()
   std::atomic<long*> a(nullptr);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  a.wait(nullptr);
 		  if (a.load() == &aa)
 		    a.store(&bb);
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(&aa);
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
index 991713fbcdee..5d5e06dde31c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/wait_notify/1.cc
@@ -36,18 +36,22 @@ main()
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   std::atomic_flag a;
   std::atomic_flag b;
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  a.wait(false);
 		  b.test_and_set();
 		  b.notify_one();
 		});
 
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.test_and_set();
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
index b38fc206d468..bc5a7d0d8bf9 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -37,17 +37,21 @@ Tp check_wait_notify(Tp val1, Tp val2)
 
   std::mutex m;
   std::condition_variable cv;
+  std::unique_lock<std::mutex> l(m);
 
   Tp aa = val1;
   std::atomic_ref<Tp> a(aa);
   std::thread t([&]
 		{
+		  {
+		    // This ensures we block until cv.wait(l) starts.
+		    std::lock_guard<std::mutex> ll(m);
+		  }
 		  cv.notify_one();
 		  a.wait(val1);
 		  if (a.load() != val2)
 		    a = val1;
 		});
-  std::unique_lock<std::mutex> l(m);
   cv.wait(l);
   std::this_thread::sleep_for(100ms);
   a.store(val2);

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] Add C++2a synchronization support
@ 2020-06-06 21:24 Thomas Rodgers
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Rodgers @ 2020-06-06 21:24 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: trodgers, Thomas Rodgers

Add support for -
        atomic wait/notify_one/notify_all
        counting_semaphore
        binary_semaphore
        latch

        * include/Makefile.am (bits_headers): Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/atomic_base.h (__atomic_base<_Itp>::wait): Define.
	(__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.h: New File.
        * 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_futex.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       | 161 +++++++++-
 libstdc++-v3/include/bits/atomic_timed_wait.h | 282 +++++++++++++++++
 libstdc++-v3/include/bits/atomic_wait.h       | 291 ++++++++++++++++++
 libstdc++-v3/include/bits/semaphore_base.h    | 272 ++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 libstdc++-v3/include/std/latch                |  90 ++++++
 libstdc++-v3/include/std/semaphore            |  86 ++++++
 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.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 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          |  28 ++
 .../30_threads/semaphore/try_acquire.cc       |  55 ++++
 .../30_threads/semaphore/try_acquire_for.cc   |  85 +++++
 .../30_threads/semaphore/try_acquire_futex.cc |  51 +++
 .../30_threads/semaphore/try_acquire_posix.cc | 169 ++++++++++
 .../30_threads/semaphore/try_acquire_until.cc |  94 ++++++
 27 files changed, 2291 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.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/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_futex.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 80aeb3f8959..b3ac1a3365f 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 \
@@ -100,6 +102,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 \
@@ -174,6 +178,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/Makefile.in b/libstdc++-v3/include/Makefile.in
index eb437ad8d8d..e73ff8b3e64 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -397,6 +397,7 @@ std_headers = \
 	${std_srcdir}/iostream \
 	${std_srcdir}/istream \
 	${std_srcdir}/iterator \
+	${std_srcdir}/latch\
 	${std_srcdir}/limits \
 	${std_srcdir}/list \
 	${std_srcdir}/locale \
@@ -414,6 +415,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 \
@@ -445,6 +447,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 \
@@ -519,6 +523,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 3b66b040976..68d9e7e3756 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;
@@ -562,6 +565,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
@@ -823,6 +851,30 @@ _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
@@ -911,6 +963,32 @@ _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
@@ -1164,6 +1242,23 @@ _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
@@ -1301,6 +1396,22 @@ _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); }
+
     private:
       _Tp* _M_ptr;
     };
@@ -1396,6 +1507,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1551,6 +1678,22 @@ _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); }
+
       value_type
       fetch_add(value_type __i,
 		memory_order __m = memory_order_seq_cst) const noexcept
@@ -1660,6 +1803,22 @@ _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); }
+
       _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..adef80aca61
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,282 @@
+// -*- 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
+    enum
+    {
+      __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+      __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+      __futex_bitset_match_any = 0xffffffff
+    };
+
+    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, __futex_wait_bitset_private, __val, &__rt,
+			    nullptr, __futex_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 (std::is_same_v<__platform_wait_clock_t, _Clock>)
+	  {
+	    return __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 (__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 (__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 (__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 (__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..92c1e2526ed
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,291 @@
+// -*- 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
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// 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;
+
+    inline constexpr
+    auto __platform_wait_max_value =
+		__gnu_cxx::__numeric_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
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+      __futex_private_flag = 128,
+#else
+      __futex_private_flag = 0,
+#endif
+      __futex_wait = 0,
+      __futex_wake = 1,
+      __futex_wait_bitset = 9,
+      __futex_wake_bitset = 10,
+      __futex_wait_private = __futex_wait | __futex_private_flag,
+      __futex_wake_private = __futex_wake | __futex_private_flag
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+    {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && !(errno == EINTR || errno == EAGAIN))
+	 std::terminate();
+    }
+
+    void
+    __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+    {
+      syscall (SYS_futex, __addr, __futex_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(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((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 < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	{
+	  if (__pred())
+	    return true;
+
+	  if (__i < _GLIBCXX_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((__platform_wait_t*)(void*) __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..f0c4235d91c
--- /dev/null
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -0,0 +1,272 @@
+// -*- 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 defined _POSIX_SEMAPHORES  && __has_include(<semaphore.h>)
+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
+#include <semaphore.h>
+#endif
+
+#include <chrono>
+#include <type_traits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    struct __platform_semaphore
+    {
+      using __clock_t = chrono::system_clock;
+
+      explicit __platform_semaphore(ptrdiff_t __count) noexcept
+      {
+	static_assert( __least_max_value <= SEM_VALUE_MAX, "");
+	auto __e = sem_init(&_M_semaphore, 0, __count);
+	if (__e)
+	  std::terminate();
+      }
+
+      ~__platform_semaphore()
+      {
+	auto __e = sem_destroy(&_M_semaphore);
+	if (__e)
+	  std::terminate();
+      }
+
+      _GLIBCXX_ALWAYS_INLINE void
+      acquire() noexcept
+      {
+	auto __err = sem_wait(&_M_semaphore);
+	if (__err)
+	  std::terminate();
+      }
+
+      template<typename _Duration>
+	bool
+	__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())
+	  };
+
+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
+	  if (__err && (errno == ETIMEDOUT))
+	      return false;
+	  else if (__err)
+	      std::terminate();
+	  return true;
+	}
+
+      template<typename _Clock, typename _Duration>
+	bool
+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+	{
+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
+	    {
+	      return __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 (__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
+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+	{ return try_acquire_until(__clock_t::now() + __rtime); }
+
+      template<typename _Clock, typename _Duration>
+	_GLIBCXX_ALWAYS_INLINE void
+	release(ptrdiff_t __update) noexcept
+	{
+	  do
+	    {
+	      auto __err = sem_post(&_M_semaphore);
+	      if (__err)
+		std::terminate();
+	    } while (--__update);
+	}
+
+      private:
+	sem_t _M_semaphore;
+      };
+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
+
+    template<typename _Tp>
+      struct __atomic_semaphore
+      {
+	explicit __atomic_semaphore(_Tp __count)
+	  : _M_a(__count)
+	{ }
+
+	_GLIBCXX_ALWAYS_INLINE void
+	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
+	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
+	  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
+	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
+      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_REQUIRE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __platform_semaphore<__least_max_value>;
+#else
+#  ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= __detail::__platform_wait_max_value),
+			      __atomic_semaphore<__detail::__platform_wait_t>,
+			      __atomic_semaphore<ptrdiff_t>>;
+
+// __platform_semaphore
+#  elif defined _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = conditional_t<(
+			      __least_max_value >= 0
+				&& __least_max_value <= SEM_VALUE_MAX),
+			      __platform_semaphore<__least_max_value>,
+			      __atomic_semaphore<ptrdiff_t>>;
+#  else
+  template<ptrdiff_t __least_max_value>
+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
+#  endif
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index a455286a784..3f18774031d 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
@@ -352,6 +365,19 @@ _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) noexcept
+    { _M_i.wait(__old, __m); }
+
+    // TODO add const volatile overload
+
+    void notify_one() const noexcept
+    { _M_i.notify_one(); }
+
+    void notify_all() const noexcept
+    { _M_i.notify_all(); }
+#endif
+
     };
 #undef _GLIBCXX20_INIT
 
@@ -590,6 +616,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
@@ -1342,6 +1380,29 @@ _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..aa5299d9fdd
--- /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
+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+    max() noexcept
+    { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+    constexpr explicit latch(ptrdiff_t __expected) : _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..90cf3244647
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,86 @@
+// <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_base<__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)
+      { _M_sem.release(__update); }
+
+      void acquire()
+      { _M_sem.acquire(); }
+
+      bool try_acquire() noexcept
+      { return _M_sem.try_acquire(); }
+
+      template<class _Rep, class _Period>
+	bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+	{ return _M_sem.try_acquire_for(__rel_time); }
+
+      template<class _Clock, class _Duration>
+	bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+	{ return _M_sem.try_acquire_until(__abs_time); }
+    };
+
+ 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 c6bde2cfbda..f09da3344f7 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -189,6 +189,8 @@
 #endif
 #define __cpp_lib_type_identity 201806L
 #define __cpp_lib_unwrap_ref 201811L
+#define __cpp_lib_semaphore 201907L
+#define __cpp_lib_latch 201907L
 
 #if _GLIBCXX_HOSTED
 #undef __cpp_lib_array_constexpr
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.h b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
new file mode 100644
index 00000000000..0da374ece87
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,88 @@
+// -*- 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.
+
+// 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 <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;
+
+  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_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);
+		  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>
+struct check
+{
+  check()
+  {
+    Tp a = 0;
+    Tp b = 42;
+    VERIFY(check_wait_notify(a, b) == b);
+    VERIFY(check_atomic_wait_notify(a, b) == b);
+  }
+};
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..2afd19a7d14
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
@@ -0,0 +1,56 @@
+// { 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 ()
+{
+  // 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/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..756727f33b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..10bb500d261
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019-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..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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..1ac9d261ca5
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2019-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>
+
+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..d38cef86cfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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..965554a3c28
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2019-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_futex.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
new file mode 100644
index 00000000000..5e05606e97f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_futex.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+void test01()
+{
+  // the implementation optimizes for values of least_max_t that can fit
+  // in a futex, make sure we cover the case where least_max_t doesn't
+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
+  std::counting_semaphore<least_max_t> s(3);
+
+  s.acquire();
+  VERIFY( s.try_acquire() );
+  VERIFY( s.try_acquire() );
+  VERIFY( !s.try_acquire() );
+  s.release();
+  VERIFY( s.try_acquire() );
+}
+
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+  test01();
+#endif
+}
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..bf99fd3cf8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
@@ -0,0 +1,169 @@
+// Copyright (C) 2019-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>
+
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  // The implementation supports posix as an implementation strategy
+  // make sure we cover that case
+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE
+
+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()
+{
+  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 test03()
+{
+  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);
+}
+
+void test04()
+{
+  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 test05()
+{
+  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);
+}
+#endif
+
+int main()
+{
+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+#endif
+}
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..cc67c5c0bf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std::chrono_literals;
+  std::counting_semaphore<10> s(2);
+  s.acquire();
+
+  auto const dur = 250ms;
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff < dur );
+  }
+
+  {
+    auto const at = std::chrono::system_clock::now() + dur;
+    auto const t0 = std::chrono::steady_clock::now();
+    VERIFY( !s.try_acquire_until(at) );
+    auto const diff = std::chrono::steady_clock::now() - t0;
+    VERIFY( diff >= dur );
+  }
+}
+
+void test02()
+{
+  using namespace std::chrono_literals;
+  std::binary_semaphore s(1);
+  std::atomic<int> a(0), b(0);
+  std::thread t([&] {
+    a.wait(0);
+    auto const dur = 250ms;
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( !s.try_acquire_until(at) );
+
+      b++;
+      b.notify_one();
+    }
+
+    a.wait(1);
+    {
+      auto const at = std::chrono::system_clock::now() + dur;
+      VERIFY( s.try_acquire_until(at) );
+    }
+    b++;
+    b.notify_one();
+  });
+  t.detach();
+
+  s.acquire();
+  a++;
+  a.notify_one();
+  b.wait(0);
+  s.release();
+  a++;
+  a.notify_one();
+
+  b.wait(1);
+}
+
+int main()
+{
+  test01();
+  test02();
+}
-- 
2.26.2


^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2020-11-26 16:26 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-10  0:01 [PATCH] Add C++2a synchronization support Thomas Rodgers
2020-05-11 14:05 ` Jonathan Wakely
2020-05-11 15:43   ` Thomas Rodgers
2020-05-11 17:05     ` Jonathan Wakely
2020-05-11 20:59   ` Thomas Rodgers
2020-05-23 22:52     ` Thomas Rodgers
2020-05-24 17:41       ` Thomas Rodgers
2020-06-06  0:29       ` Thomas Rodgers
2020-07-08 16:43         ` Jonathan Wakely
2020-08-03 14:09         ` Jonathan Wakely
2020-08-03 20:19           ` Jonathan Wakely
2020-09-03  0:47             ` Thomas Rodgers
2020-09-03  0:54               ` Thomas Rodgers
2020-09-11 23:58                 ` [PATCH] libstdc++: " Thomas Rodgers
2020-09-28 13:25                   ` Jonathan Wakely
2020-10-01 23:37                     ` Thomas Rodgers
2020-10-02 15:40                       ` Thomas Rodgers
2020-10-05 22:54                       ` [PATCH] t/trodgers/c2a_synchronization Thomas Rodgers
2020-10-23 10:28                         ` Jonathan Wakely
2020-10-26 21:48                           ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
2020-10-27 10:23                             ` Jonathan Wakely
2020-11-20 22:44                               ` Thomas Rodgers
2020-11-22 21:13                                 ` Stephan Bergmann
2020-11-23 18:33                                   ` Jonathan Wakely
2020-11-22 21:41                                 ` Stephan Bergmann
2020-11-23 18:32                                   ` Jonathan Wakely
2020-11-21 15:16                             ` Andreas Schwab
2020-11-21 17:04                               ` Jonathan Wakely
2020-11-21 17:39                                 ` Jonathan Wakely
2020-11-22  0:36                                   ` H.J. Lu
2020-11-23 14:50                                     ` Jonathan Wakely
2020-11-24 23:45                                     ` Jonathan Wakely
2020-11-25  1:07                                       ` Jonathan Wakely
2020-11-25 10:35                                         ` Jonathan Wakely
2020-11-25 12:32                                           ` Jonathan Wakely
2020-11-25 18:39                                           ` Jonathan Wakely
2020-11-26 16:26                                             ` Jonathan Wakely
2020-11-23 16:08                                   ` Jonathan Wakely
2020-09-28 13:30                   ` Jonathan Wakely
2020-09-28 13:36                   ` Jonathan Wakely
2020-09-28 21:29                     ` Thomas Rodgers
2020-09-29  9:44                       ` Jonathan Wakely
2020-06-06 21:24 [PATCH] " Thomas Rodgers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).