I *think* I have addressed everything in the attached patch.
commit 24a989d2bf2158bdbe2511310d0583d0c6226f71
Author: Thomas Rodgers <rodg...@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();
+}
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...

Reply via email to