Add C++2a wait/notify_one/notify_all support to std::atomic<>

Message ID 20200316004336.1531416-1-rodgert@appliantology.com
State New
Headers show
Series
  • Add C++2a wait/notify_one/notify_all support to std::atomic<>
Related show

Commit Message

Thomas Rodgers March 16, 2020, 12:43 a.m.
This patch adds support for wait/notify_one/notify_all to std::atomic<>.
Support for the volatile overloads will be added in a subsequent patch.

	* include/Makefile.am (bits_headers): Add new header.
	* include/Mamefile.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/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.
	* 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.
---
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   2 +
 libstdc++-v3/include/bits/atomic_base.h       | 178 ++++++++++-
 libstdc++-v3/include/bits/atomic_wait.h       | 295 ++++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
 .../29_atomics/atomic/wait_notify/bool.cc     |  57 ++++
 .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
 .../29_atomics/atomic/wait_notify/generic.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 11 files changed, 931 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc

-- 
2.24.1

Comments

Jeff Law via Gcc-patches March 17, 2020, 8:25 p.m. | #1
Updated patch attached, addresses some minor issues I found after
sending the original version.
From 0c677da72a058e37d0ea1975dc70e53c4308963c Mon Sep 17 00:00:00 2001
From: Thomas Rodgers <rodgert@appliantology.com>

Date: Thu, 12 Mar 2020 17:50:09 -0700
Subject: [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<>

This patch adds support for wait/notify_one/notify_all to std::atomic<>.
Support for the volatile overloads will be added in a subsequent patch.

	* include/Makefile.am (bits_headers): Add new header.
	* include/Mamefile.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/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.
	* 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.
---
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   2 +
 libstdc++-v3/include/bits/atomic_base.h       | 178 ++++++++++-
 libstdc++-v3/include/bits/atomic_wait.h       | 295 ++++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++
 .../29_atomics/atomic/wait_notify/bool.cc     |  57 ++++
 .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
 .../29_atomics/atomic/wait_notify/generic.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 11 files changed, 931 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 80aeb3f8959..d195a721fd5 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -100,6 +100,7 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index eb437ad8d8d..4faaac5fb8d 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -445,6 +445,7 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
@@ -526,6 +527,7 @@ bits_headers = \
 	${bits_srcdir}/specfun.h \
 	${bits_srcdir}/sstream.tcc \
 	${bits_srcdir}/std_abs.h \
+	${bits_srcdir}/std_condvar.h \
 	${bits_srcdir}/std_function.h \
 	${bits_srcdir}/std_mutex.h \
 	${bits_srcdir}/stl_algo.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 87fe0bd6000..b4fbe2c6eb3 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,11 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#include <iostream>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -542,6 +546,35 @@ _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
+      {
+	__detail::__atomic_wait(&_M_i, __old, [__m, this](__int_type __o)
+					      {
+						return this->load(__m) == __o;
+					      });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      {
+	__detail::__atomic_notify(&_M_i, false);
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      {
+	__detail::__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 +836,35 @@ _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
+      {
+	__detail::__atomic_wait(&_M_p, __old, [__m, this](__pointer_type __o)
+					      {
+						return this->load(__m) == __o;
+					      });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      {
+	__detail::__atomic_notify(&_M_p, false);
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      {
+	__detail::__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 +953,39 @@ _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
+      {
+	__detail::__atomic_wait_ptr(__ptr, std::__addressof(__old),
+				    [=](_Tp* __o)
+				    {
+				      return load(__ptr, __m) == *__o;
+				    });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      {
+	__detail::__atomic_notify(__ptr, false);
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      {
+	__detail::__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 +1239,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 +1393,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 +1504,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 +1675,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 +1800,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_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..fa2650afc39
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,295 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    template<class _Tp>
+      struct __platform_wait_uses_type
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
+				      __platform_wait_t>::value };
+#else
+	enum { __value = std::false_type::value };
+#endif
+      };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+     __futex_private_flag = 128,
+#else
+     __futex_private_flag = 0,
+#endif
+     __futex_wait = 0,
+     __futex_wake = 1,
+     __futex_wait_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) __waiter
+    {
+      bool _M_signaled = false;
+      void* _M_t;
+      __waiter* _M_prev = nullptr;
+      __waiter* _M_next = nullptr;
+
+      __waiter(void* __t) noexcept
+      : _M_t(__t)
+      { }
+    };
+
+    struct alignas(64) __waiters
+    {
+      int32_t alignas(64) _M_ver = 0;
+      int32_t alignas(64) _M_wait = 0;
+
+      // TODO make this used only where we don't have futexes
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#endif
+
+      int32_t
+      _M_enter_wait() noexcept
+      {
+	int32_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(int32_t __version) const noexcept
+      {
+	int32_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      std::terminate();
+	    int32_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    // protect if version overflows
+	    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];
+      }
+    };
+
+    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
+    }
+
+    template<class _Tp, class _Pred>
+      void
+      __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+     {
+	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	  {
+	    if (!__pred(__old))
+	      return;
+
+	    if (__i < _GLIBCXX_SPIN_COUNT_2)
+	      __thread_relax();
+	    else
+	      __thread_yield();
+	  }
+
+	auto& __w = __waiters::_S_for((void*)__addr);
+	auto __version = __w._M_enter_wait();
+	while (auto __res = __pred(__old))
+	  {
+	    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(__version);
+	      }
+	  }
+	__w._M_leave_wait();
+      }
+
+    template<class _Tp, class _Pred>
+      void
+      __atomic_wait_ptr(const _Tp* __addr, _Tp* __old, _Pred __pred) noexcept
+     {
+	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	  {
+	    if (!__pred(__old))
+	      return;
+
+	    if (__i < _GLIBCXX_SPIN_COUNT_2)
+	      __thread_relax();
+	    else
+	      __thread_yield();
+	  }
+
+	auto& __w = __waiters::_S_for((void*)__addr);
+	auto __version = __w._M_enter_wait();
+	while (auto __res = __pred(__old))
+	  {
+	    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(__version);
+	      }
+	  }
+	__w._M_leave_wait();
+      }
+
+    template<class _Tp>
+      void
+      __atomic_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	auto& __w = __waiters::_S_for((void*)__addr);
+	if (!__w._M_waiting())
+	  return;
+
+	if constexpr (__platform_wait_uses_type<_Tp>::__value)
+	  {
+	    __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	  }
+	else
+	  {
+	    __w._M_notify(__all);
+	  }
+      }
+  } // namespace __detail
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
+
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 40f23bdfc96..cb2308b0cdf 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/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..1d8d13621cc
--- /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..98258686945
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,57 @@
+// { 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..e6eeebf4ab2
--- /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..fe0b8de9f3f
--- /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;
+}
-- 
2.24.1
Thomas Rodgers writes:

> This patch adds support for wait/notify_one/notify_all to std::atomic<>.

> Support for the volatile overloads will be added in a subsequent patch.

>

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

> 	* 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.

> ---

>  libstdc++-v3/include/Makefile.am              |   1 +

>  libstdc++-v3/include/Makefile.in              |   2 +

>  libstdc++-v3/include/bits/atomic_base.h       | 178 ++++++++++-

>  libstdc++-v3/include/bits/atomic_wait.h       | 295 ++++++++++++++++++

>  libstdc++-v3/include/std/atomic               |  61 ++++

>  .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++

>  .../29_atomics/atomic/wait_notify/bool.cc     |  57 ++++

>  .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++

>  .../29_atomics/atomic/wait_notify/generic.h   |  88 ++++++

>  .../atomic/wait_notify/integrals.cc           |  56 ++++

>  .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++

>  11 files changed, 931 insertions(+), 1 deletion(-)

>  create mode 100644 libstdc++-v3/include/bits/atomic_wait.h

>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc

>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc

>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc

>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h

>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc

>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc

>

> diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am

> index 80aeb3f8959..d195a721fd5 100644

> --- a/libstdc++-v3/include/Makefile.am

> +++ b/libstdc++-v3/include/Makefile.am

> @@ -100,6 +100,7 @@ bits_headers = \

>  	${bits_srcdir}/allocated_ptr.h \

>  	${bits_srcdir}/allocator.h \

>  	${bits_srcdir}/atomic_base.h \

> +	${bits_srcdir}/atomic_wait.h \

>  	${bits_srcdir}/atomic_futex.h \

>  	${bits_srcdir}/basic_ios.h \

>  	${bits_srcdir}/basic_ios.tcc \

> diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in

> index eb437ad8d8d..4faaac5fb8d 100644

> --- a/libstdc++-v3/include/Makefile.in

> +++ b/libstdc++-v3/include/Makefile.in

> @@ -445,6 +445,7 @@ bits_headers = \

>  	${bits_srcdir}/allocated_ptr.h \

>  	${bits_srcdir}/allocator.h \

>  	${bits_srcdir}/atomic_base.h \

> +	${bits_srcdir}/atomic_wait.h \

>  	${bits_srcdir}/atomic_futex.h \

>  	${bits_srcdir}/basic_ios.h \

>  	${bits_srcdir}/basic_ios.tcc \

> @@ -526,6 +527,7 @@ bits_headers = \

>  	${bits_srcdir}/specfun.h \

>  	${bits_srcdir}/sstream.tcc \

>  	${bits_srcdir}/std_abs.h \

> +	${bits_srcdir}/std_condvar.h \

>  	${bits_srcdir}/std_function.h \

>  	${bits_srcdir}/std_mutex.h \

>  	${bits_srcdir}/stl_algo.h \

> diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h

> index 87fe0bd6000..b4fbe2c6eb3 100644

> --- a/libstdc++-v3/include/bits/atomic_base.h

> +++ b/libstdc++-v3/include/bits/atomic_base.h

> @@ -37,6 +37,11 @@

>  #include <bits/atomic_lockfree_defines.h>

>  #include <bits/move.h>

>  

> +#if __cplusplus > 201703L

> +#include <bits/atomic_wait.h>

> +#include <iostream>

> +#endif

> +

>  #ifndef _GLIBCXX_ALWAYS_INLINE

>  #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))

>  #endif

> @@ -134,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

>        return __ret;

>      }

>  

> -

>    // Base types for atomics.

>    template<typename _IntTp>

>      struct __atomic_base;

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

> +      {

> +	__detail::__atomic_wait(&_M_i, __old, [__m, this](__int_type __o)

> +					      {

> +						return this->load(__m) == __o;

> +					      });

> +      }

> +

> +      // TODO add const volatile overload

> +

> +      _GLIBCXX_ALWAYS_INLINE void

> +      notify_one() const noexcept

> +      {

> +	__detail::__atomic_notify(&_M_i, false);

> +      }

> +

> +      // TODO add const volatile overload

> +

> +      _GLIBCXX_ALWAYS_INLINE void

> +      notify_all() const noexcept

> +      {

> +	__detail::__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 +836,35 @@ _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

> +      {

> +	__detail::__atomic_wait(&_M_p, __old, [__m, this](__pointer_type __o)

> +					      {

> +						return this->load(__m) == __o;

> +					      });

> +      }

> +

> +      // TODO add const volatile overload

> +

> +      _GLIBCXX_ALWAYS_INLINE void

> +      notify_one() const noexcept

> +      {

> +	__detail::__atomic_notify(&_M_p, false);

> +      }

> +

> +      // TODO add const volatile overload

> +

> +      _GLIBCXX_ALWAYS_INLINE void

> +      notify_all() const noexcept

> +      {

> +	__detail::__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 +953,39 @@ _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

> +      {

> +	__detail::__atomic_wait_ptr(__ptr, std::__addressof(__old),

> +				    [=](_Tp* __o)

> +				    {

> +				      return load(__ptr, __m) == *__o;

> +				    });

> +      }

> +

> +      // TODO add const volatile overload

> +

> +    template<typename _Tp>

> +      _GLIBCXX_ALWAYS_INLINE void

> +      notify_one(const _Tp* __ptr) noexcept

> +      {

> +	__detail::__atomic_notify(__ptr, false);

> +      }

> +

> +      // TODO add const volatile overload

> +

> +    template<typename _Tp>

> +      _GLIBCXX_ALWAYS_INLINE void

> +      notify_all(const _Tp* __ptr) noexcept

> +      {

> +	__detail::__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 +1239,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 +1393,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 +1504,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 +1675,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 +1800,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_wait.h b/libstdc++-v3/include/bits/atomic_wait.h

> new file mode 100644

> index 00000000000..fa2650afc39

> --- /dev/null

> +++ b/libstdc++-v3/include/bits/atomic_wait.h

> @@ -0,0 +1,295 @@

> +// -*- C++ -*- header.

> +

> +// Copyright (C) 2020 Free Software Foundation, Inc.

> +//

> +// This file is part of the GNU ISO C++ Library.  This library is free

> +// software; you can redistribute it and/or modify it under the

> +// terms of the GNU General Public License as published by the

> +// Free Software Foundation; either version 3, or (at your option)

> +// any later version.

> +

> +// This library is distributed in the hope that it will be useful,

> +// but WITHOUT ANY WARRANTY; without even the implied warranty of

> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

> +// GNU General Public License for more details.

> +

> +// Under Section 7 of GPL version 3, you are granted additional

> +// permissions described in the GCC Runtime Library Exception, version

> +// 3.1, as published by the Free Software Foundation.

> +

> +// You should have received a copy of the GNU General Public License and

> +// a copy of the GCC Runtime Library Exception along with this program;

> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

> +// <http://www.gnu.org/licenses/>.

> +

> +/** @file bits/atomic_wait.h

> + *  This is an internal header file, included by other library headers.

> + *  Do not attempt to use it directly. @headername{atomic}

> + */

> +

> +#ifndef _GLIBCXX_ATOMIC_WAIT_H

> +#define _GLIBCXX_ATOMIC_WAIT_H 1

> +

> +#pragma GCC system_header

> +

> +#include <bits/c++config.h>

> +#include <bits/functional_hash.h>

> +#include <bits/gthr.h>

> +#include <bits/std_mutex.h>

> +#include <bits/unique_lock.h>

> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX

> +#include <climits>

> +#include <unistd.h>

> +#include <syscall.h>

> +#endif

> +

> +#define _GLIBCXX_SPIN_COUNT_1 16

> +#define _GLIBCXX_SPIN_COUNT_2 12

> +

> +// TODO get this from Autoconf

> +#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1

> +

> +namespace std _GLIBCXX_VISIBILITY(default)

> +{

> +_GLIBCXX_BEGIN_NAMESPACE_VERSION

> +  namespace __detail

> +  {

> +    using __platform_wait_t = int;

> +

> +    template<class _Tp>

> +      struct __platform_wait_uses_type

> +      {

> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX

> +	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,

> +				      __platform_wait_t>::value };

> +#else

> +	enum { __value = std::false_type::value };

> +#endif

> +      };

> +

> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX

> +    enum

> +    {

> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE

> +     __futex_private_flag = 128,

> +#else

> +     __futex_private_flag = 0,

> +#endif

> +     __futex_wait = 0,

> +     __futex_wake = 1,

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

> +    {

> +      bool _M_signaled = false;

> +      void* _M_t;

> +      __waiter* _M_prev = nullptr;

> +      __waiter* _M_next = nullptr;

> +

> +      __waiter(void* __t) noexcept

> +      : _M_t(__t)

> +      { }

> +    };

> +

> +    struct alignas(64) __waiters

> +    {

> +      int32_t alignas(64) _M_ver = 0;

> +      int32_t alignas(64) _M_wait = 0;

> +

> +      // TODO make this used only where we don't have futexes

> +      using __lock_t = std::unique_lock<std::mutex>;

> +      mutable __lock_t::mutex_type _M_mtx;

> +

> +#ifdef __GTHREAD_COND_INIT

> +      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;

> +      __waiters() noexcept = default;

> +#else

> +      mutable __gthread_cond_t _M_cv;

> +      __waiters() noexcept

> +      {

> +	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);

> +      }

> +#endif

> +

> +      int32_t

> +      _M_enter_wait() noexcept

> +      {

> +	int32_t __res;

> +	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);

> +	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);

> +	return __res;

> +      }

> +

> +      void

> +      _M_leave_wait() noexcept

> +      {

> +	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);

> +      }

> +

> +      void

> +      _M_do_wait(int32_t __version) const noexcept

> +      {

> +	int32_t __cur = 0;

> +	while (__cur <= __version)

> +	  {

> +	    __waiters::__lock_t __l(_M_mtx);

> +	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());

> +	    if (__e)

> +	      std::terminate();

> +	    int32_t __last = __cur;

> +	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);

> +	    // protect if version overflows

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

> +      }

> +    };

> +

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

> +    }

> +

> +    template<class _Tp, class _Pred>

> +      void

> +      __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept

> +     {

> +	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)

> +	  {

> +	    if (!__pred(__old))

> +	      return;

> +

> +	    if (__i < _GLIBCXX_SPIN_COUNT_2)

> +	      __thread_relax();

> +	    else

> +	      __thread_yield();

> +	  }

> +

> +	auto& __w = __waiters::_S_for((void*)__addr);

> +	auto __version = __w._M_enter_wait();

> +	while (auto __res = __pred(__old))

> +	  {

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

> +	      }

> +	  }

> +	__w._M_leave_wait();

> +      }

> +

> +    template<class _Tp, class _Pred>

> +      void

> +      __atomic_wait_ptr(const _Tp* __addr, _Tp* __old, _Pred __pred) noexcept

> +     {

> +	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)

> +	  {

> +	    if (!__pred(__old))

> +	      return;

> +

> +	    if (__i < _GLIBCXX_SPIN_COUNT_2)

> +	      __thread_relax();

> +	    else

> +	      __thread_yield();

> +	  }

> +

> +	auto& __w = __waiters::_S_for((void*)__addr);

> +	auto __version = __w._M_enter_wait();

> +	while (auto __res = __pred(__old))

> +	  {

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

> +	      }

> +	  }

> +	__w._M_leave_wait();

> +      }

> +

> +    template<class _Tp>

> +      void

> +      __atomic_notify(const _Tp* __addr, bool __all) noexcept

> +      {

> +	auto& __w = __waiters::_S_for((void*)__addr);

> +	if (!__w._M_waiting())

> +	  return;

> +

> +	if constexpr (__platform_wait_uses_type<_Tp>::__value)

> +	  {

> +	    __platform_notify((__platform_wait_t*)(void*) __addr, __all);

> +	  }

> +	else

> +	  {

> +	    __w._M_notify(__all);

> +	  }

> +      }

> +  } // namespace __detail

> +

> +_GLIBCXX_END_NAMESPACE_VERSION

> +} // namespace std

> +

> +#endif

> +

> diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic

> index 40f23bdfc96..cb2308b0cdf 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/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..1d8d13621cc

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

> --- /dev/null

> +++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc

> @@ -0,0 +1,57 @@

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

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

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

> +}
Jeff Law via Gcc-patches March 24, 2020, 12:09 a.m. | #2
Updated patch, fixes some whitespace issues along with ensuring that
libstdc++-v3/include/Makefile.in is regenerated.
From 2f707faab97abde776bc7c6e06f7a7c471711962 Mon Sep 17 00:00:00 2001
From: Thomas Rodgers <rodgert@appliantology.com>

Date: Thu, 12 Mar 2020 17:50:09 -0700
Subject: [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<>

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

Tested x86_64-pc-linux-gnu.
---
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   1 +
 libstdc++-v3/include/bits/atomic_base.h       | 178 ++++++++++-
 libstdc++-v3/include/bits/atomic_wait.h       | 284 ++++++++++++++++++
 libstdc++-v3/include/std/atomic               |  61 ++++
 .../atomic/wait_notify/atomic_refs.cc         | 103 +++++++
 .../29_atomics/atomic/wait_notify/bool.cc     |  57 ++++
 .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++
 .../29_atomics/atomic/wait_notify/generic.h   |  88 ++++++
 .../atomic/wait_notify/integrals.cc           |  56 ++++
 .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++
 11 files changed, 919 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/bits/atomic_wait.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
 create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 80aeb3f8959..d195a721fd5 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -100,6 +100,7 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index eb437ad8d8d..f19c3342f06 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -445,6 +445,7 @@ bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 87fe0bd6000..b4fbe2c6eb3 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,11 @@
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#include <iostream>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -542,6 +546,35 @@ _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
+      {
+	__detail::__atomic_wait(&_M_i, __old, [__m, this](__int_type __o)
+					      {
+						return this->load(__m) == __o;
+					      });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      {
+	__detail::__atomic_notify(&_M_i, false);
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      {
+	__detail::__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 +836,35 @@ _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
+      {
+	__detail::__atomic_wait(&_M_p, __old, [__m, this](__pointer_type __o)
+					      {
+						return this->load(__m) == __o;
+					      });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      {
+	__detail::__atomic_notify(&_M_p, false);
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      {
+	__detail::__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 +953,39 @@ _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
+      {
+	__detail::__atomic_wait_ptr(__ptr, std::__addressof(__old),
+				    [=](_Tp* __o)
+				    {
+				      return load(__ptr, __m) == *__o;
+				    });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      {
+	__detail::__atomic_notify(__ptr, false);
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      {
+	__detail::__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 +1239,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 +1393,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 +1504,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 +1675,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 +1800,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_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..c33e25e5ddf
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,284 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    template<class _Tp>
+      struct __platform_wait_uses_type
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
+				      __platform_wait_t>::value };
+#else
+	enum { __value = std::false_type::value };
+#endif
+      };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+     __futex_private_flag = 128,
+#else
+     __futex_private_flag = 0,
+#endif
+     __futex_wait = 0,
+     __futex_wake = 1,
+     __futex_wait_private = __futex_wait | __futex_private_flag,
+     __futex_wake_private = __futex_wake | __futex_private_flag,
+    };
+
+    void
+    __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+     {
+       auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+       if (__e && (errno != EINTR || errno != EAGAIN))
+	 std::terminate();
+     }
+
+     void
+     __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+     {
+       syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
+     }
+#endif
+
+    struct alignas(64) __waiters
+    {
+      int32_t alignas(64) _M_ver = 0;
+      int32_t alignas(64) _M_wait = 0;
+
+      // TODO make this used only where we don't have futexes
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#endif
+
+      int32_t
+      _M_enter_wait() noexcept
+      {
+	int32_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(int32_t __version) const noexcept
+      {
+	int32_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      std::terminate();
+	    int32_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    // protect if version overflows
+	    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];
+      }
+    };
+
+    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
+    }
+
+    template<class _Tp, class _Pred>
+      bool
+      __atomic_spin1(_Tp __old, _Pred __pred) noexcept
+      {
+	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	  {
+	    if (!__pred(__old))
+	      return true;
+
+	    if (__i < _GLIBCXX_SPIN_COUNT_2)
+	      __thread_relax();
+	    else
+	      __thread_yield();
+	  }
+	return false;
+      }
+
+    template<class _Tp, class _Pred>
+      void
+      __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+     {
+       if (__atomic_spin1(__old, __pred))
+	 return;
+
+       auto& __w = __waiters::_S_for((void*)__addr);
+       auto __version = __w._M_enter_wait();
+       while (__pred(__old))
+	 {
+	   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(__version);
+	     }
+	  }
+	__w._M_leave_wait();
+      }
+
+    template<class _Tp, class _Pred>
+      void
+      __atomic_wait_ptr(const _Tp* __addr, _Tp* __old, _Pred __pred) noexcept
+     {
+       if (__atomic_spin1(__old, __pred))
+	 return;
+
+	auto& __w = __waiters::_S_for((void*)__addr);
+	auto __version = __w._M_enter_wait();
+	while (__pred(__old))
+	  {
+	    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(__version);
+	      }
+	  }
+	__w._M_leave_wait();
+      }
+
+    template<class _Tp>
+      void
+      __atomic_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	auto& __w = __waiters::_S_for((void*)__addr);
+	if (!__w._M_waiting())
+	  return;
+
+	if constexpr (__platform_wait_uses_type<_Tp>::__value)
+	  {
+	    __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	  }
+	else
+	  {
+	    __w._M_notify(__all);
+	  }
+      }
+  } // namespace __detail
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 40f23bdfc96..cb2308b0cdf 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/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..3ebf50bb9a5
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,57 @@
+// { 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;
+}
-- 
2.25.1
Thomas Rodgers via Libstdc++ writes:

> Updated patch attached, addresses some minor issues I found after

> sending the original version.

>

> Thomas Rodgers writes:

>

>> This patch adds support for wait/notify_one/notify_all to std::atomic<>.

>> Support for the volatile overloads will be added in a subsequent patch.

>>

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

>> 	* 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.

>> ---

>>  libstdc++-v3/include/Makefile.am              |   1 +

>>  libstdc++-v3/include/Makefile.in              |   2 +

>>  libstdc++-v3/include/bits/atomic_base.h       | 178 ++++++++++-

>>  libstdc++-v3/include/bits/atomic_wait.h       | 295 ++++++++++++++++++

>>  libstdc++-v3/include/std/atomic               |  61 ++++

>>  .../atomic/wait_notify/atomic_refs.cc         | 103 ++++++

>>  .../29_atomics/atomic/wait_notify/bool.cc     |  57 ++++

>>  .../29_atomics/atomic/wait_notify/floats.cc   |  32 ++

>>  .../29_atomics/atomic/wait_notify/generic.h   |  88 ++++++

>>  .../atomic/wait_notify/integrals.cc           |  56 ++++

>>  .../29_atomics/atomic/wait_notify/pointers.cc |  59 ++++

>>  11 files changed, 931 insertions(+), 1 deletion(-)

>>  create mode 100644 libstdc++-v3/include/bits/atomic_wait.h

>>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/atomic_refs.cc

>>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc

>>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/floats.cc

>>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h

>>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc

>>  create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc

>>

>> diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am

>> index 80aeb3f8959..d195a721fd5 100644

>> --- a/libstdc++-v3/include/Makefile.am

>> +++ b/libstdc++-v3/include/Makefile.am

>> @@ -100,6 +100,7 @@ bits_headers = \

>>  	${bits_srcdir}/allocated_ptr.h \

>>  	${bits_srcdir}/allocator.h \

>>  	${bits_srcdir}/atomic_base.h \

>> +	${bits_srcdir}/atomic_wait.h \

>>  	${bits_srcdir}/atomic_futex.h \

>>  	${bits_srcdir}/basic_ios.h \

>>  	${bits_srcdir}/basic_ios.tcc \

>> diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in

>> index eb437ad8d8d..4faaac5fb8d 100644

>> --- a/libstdc++-v3/include/Makefile.in

>> +++ b/libstdc++-v3/include/Makefile.in

>> @@ -445,6 +445,7 @@ bits_headers = \

>>  	${bits_srcdir}/allocated_ptr.h \

>>  	${bits_srcdir}/allocator.h \

>>  	${bits_srcdir}/atomic_base.h \

>> +	${bits_srcdir}/atomic_wait.h \

>>  	${bits_srcdir}/atomic_futex.h \

>>  	${bits_srcdir}/basic_ios.h \

>>  	${bits_srcdir}/basic_ios.tcc \

>> @@ -526,6 +527,7 @@ bits_headers = \

>>  	${bits_srcdir}/specfun.h \

>>  	${bits_srcdir}/sstream.tcc \

>>  	${bits_srcdir}/std_abs.h \

>> +	${bits_srcdir}/std_condvar.h \

>>  	${bits_srcdir}/std_function.h \

>>  	${bits_srcdir}/std_mutex.h \

>>  	${bits_srcdir}/stl_algo.h \

>> diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h

>> index 87fe0bd6000..b4fbe2c6eb3 100644

>> --- a/libstdc++-v3/include/bits/atomic_base.h

>> +++ b/libstdc++-v3/include/bits/atomic_base.h

>> @@ -37,6 +37,11 @@

>>  #include <bits/atomic_lockfree_defines.h>

>>  #include <bits/move.h>

>>  

>> +#if __cplusplus > 201703L

>> +#include <bits/atomic_wait.h>

>> +#include <iostream>

>> +#endif

>> +

>>  #ifndef _GLIBCXX_ALWAYS_INLINE

>>  #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))

>>  #endif

>> @@ -134,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

>>        return __ret;

>>      }

>>  

>> -

>>    // Base types for atomics.

>>    template<typename _IntTp>

>>      struct __atomic_base;

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

>> +      {

>> +	__detail::__atomic_wait(&_M_i, __old, [__m, this](__int_type __o)

>> +					      {

>> +						return this->load(__m) == __o;

>> +					      });

>> +      }

>> +

>> +      // TODO add const volatile overload

>> +

>> +      _GLIBCXX_ALWAYS_INLINE void

>> +      notify_one() const noexcept

>> +      {

>> +	__detail::__atomic_notify(&_M_i, false);

>> +      }

>> +

>> +      // TODO add const volatile overload

>> +

>> +      _GLIBCXX_ALWAYS_INLINE void

>> +      notify_all() const noexcept

>> +      {

>> +	__detail::__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 +836,35 @@ _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

>> +      {

>> +	__detail::__atomic_wait(&_M_p, __old, [__m, this](__pointer_type __o)

>> +					      {

>> +						return this->load(__m) == __o;

>> +					      });

>> +      }

>> +

>> +      // TODO add const volatile overload

>> +

>> +      _GLIBCXX_ALWAYS_INLINE void

>> +      notify_one() const noexcept

>> +      {

>> +	__detail::__atomic_notify(&_M_p, false);

>> +      }

>> +

>> +      // TODO add const volatile overload

>> +

>> +      _GLIBCXX_ALWAYS_INLINE void

>> +      notify_all() const noexcept

>> +      {

>> +	__detail::__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 +953,39 @@ _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

>> +      {

>> +	__detail::__atomic_wait_ptr(__ptr, std::__addressof(__old),

>> +				    [=](_Tp* __o)

>> +				    {

>> +				      return load(__ptr, __m) == *__o;

>> +				    });

>> +      }

>> +

>> +      // TODO add const volatile overload

>> +

>> +    template<typename _Tp>

>> +      _GLIBCXX_ALWAYS_INLINE void

>> +      notify_one(const _Tp* __ptr) noexcept

>> +      {

>> +	__detail::__atomic_notify(__ptr, false);

>> +      }

>> +

>> +      // TODO add const volatile overload

>> +

>> +    template<typename _Tp>

>> +      _GLIBCXX_ALWAYS_INLINE void

>> +      notify_all(const _Tp* __ptr) noexcept

>> +      {

>> +	__detail::__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 +1239,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 +1393,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 +1504,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 +1675,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 +1800,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_wait.h b/libstdc++-v3/include/bits/atomic_wait.h

>> new file mode 100644

>> index 00000000000..fa2650afc39

>> --- /dev/null

>> +++ b/libstdc++-v3/include/bits/atomic_wait.h

>> @@ -0,0 +1,295 @@

>> +// -*- C++ -*- header.

>> +

>> +// Copyright (C) 2020 Free Software Foundation, Inc.

>> +//

>> +// This file is part of the GNU ISO C++ Library.  This library is free

>> +// software; you can redistribute it and/or modify it under the

>> +// terms of the GNU General Public License as published by the

>> +// Free Software Foundation; either version 3, or (at your option)

>> +// any later version.

>> +

>> +// This library is distributed in the hope that it will be useful,

>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of

>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

>> +// GNU General Public License for more details.

>> +

>> +// Under Section 7 of GPL version 3, you are granted additional

>> +// permissions described in the GCC Runtime Library Exception, version

>> +// 3.1, as published by the Free Software Foundation.

>> +

>> +// You should have received a copy of the GNU General Public License and

>> +// a copy of the GCC Runtime Library Exception along with this program;

>> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

>> +// <http://www.gnu.org/licenses/>.

>> +

>> +/** @file bits/atomic_wait.h

>> + *  This is an internal header file, included by other library headers.

>> + *  Do not attempt to use it directly. @headername{atomic}

>> + */

>> +

>> +#ifndef _GLIBCXX_ATOMIC_WAIT_H

>> +#define _GLIBCXX_ATOMIC_WAIT_H 1

>> +

>> +#pragma GCC system_header

>> +

>> +#include <bits/c++config.h>

>> +#include <bits/functional_hash.h>

>> +#include <bits/gthr.h>

>> +#include <bits/std_mutex.h>

>> +#include <bits/unique_lock.h>

>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX

>> +#include <climits>

>> +#include <unistd.h>

>> +#include <syscall.h>

>> +#endif

>> +

>> +#define _GLIBCXX_SPIN_COUNT_1 16

>> +#define _GLIBCXX_SPIN_COUNT_2 12

>> +

>> +// TODO get this from Autoconf

>> +#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1

>> +

>> +namespace std _GLIBCXX_VISIBILITY(default)

>> +{

>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION

>> +  namespace __detail

>> +  {

>> +    using __platform_wait_t = int;

>> +

>> +    template<class _Tp>

>> +      struct __platform_wait_uses_type

>> +      {

>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX

>> +	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,

>> +				      __platform_wait_t>::value };

>> +#else

>> +	enum { __value = std::false_type::value };

>> +#endif

>> +      };

>> +

>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX

>> +    enum

>> +    {

>> +#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE

>> +     __futex_private_flag = 128,

>> +#else

>> +     __futex_private_flag = 0,

>> +#endif

>> +     __futex_wait = 0,

>> +     __futex_wake = 1,

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

>> +    {

>> +      bool _M_signaled = false;

>> +      void* _M_t;

>> +      __waiter* _M_prev = nullptr;

>> +      __waiter* _M_next = nullptr;

>> +

>> +      __waiter(void* __t) noexcept

>> +      : _M_t(__t)

>> +      { }

>> +    };

>> +

>> +    struct alignas(64) __waiters

>> +    {

>> +      int32_t alignas(64) _M_ver = 0;

>> +      int32_t alignas(64) _M_wait = 0;

>> +

>> +      // TODO make this used only where we don't have futexes

>> +      using __lock_t = std::unique_lock<std::mutex>;

>> +      mutable __lock_t::mutex_type _M_mtx;

>> +

>> +#ifdef __GTHREAD_COND_INIT

>> +      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;

>> +      __waiters() noexcept = default;

>> +#else

>> +      mutable __gthread_cond_t _M_cv;

>> +      __waiters() noexcept

>> +      {

>> +	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);

>> +      }

>> +#endif

>> +

>> +      int32_t

>> +      _M_enter_wait() noexcept

>> +      {

>> +	int32_t __res;

>> +	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);

>> +	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);

>> +	return __res;

>> +      }

>> +

>> +      void

>> +      _M_leave_wait() noexcept

>> +      {

>> +	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);

>> +      }

>> +

>> +      void

>> +      _M_do_wait(int32_t __version) const noexcept

>> +      {

>> +	int32_t __cur = 0;

>> +	while (__cur <= __version)

>> +	  {

>> +	    __waiters::__lock_t __l(_M_mtx);

>> +	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());

>> +	    if (__e)

>> +	      std::terminate();

>> +	    int32_t __last = __cur;

>> +	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);

>> +	    // protect if version overflows

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

>> +      }

>> +    };

>> +

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

>> +    }

>> +

>> +    template<class _Tp, class _Pred>

>> +      void

>> +      __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept

>> +     {

>> +	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)

>> +	  {

>> +	    if (!__pred(__old))

>> +	      return;

>> +

>> +	    if (__i < _GLIBCXX_SPIN_COUNT_2)

>> +	      __thread_relax();

>> +	    else

>> +	      __thread_yield();

>> +	  }

>> +

>> +	auto& __w = __waiters::_S_for((void*)__addr);

>> +	auto __version = __w._M_enter_wait();

>> +	while (auto __res = __pred(__old))

>> +	  {

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

>> +	      }

>> +	  }

>> +	__w._M_leave_wait();

>> +      }

>> +

>> +    template<class _Tp, class _Pred>

>> +      void

>> +      __atomic_wait_ptr(const _Tp* __addr, _Tp* __old, _Pred __pred) noexcept

>> +     {

>> +	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)

>> +	  {

>> +	    if (!__pred(__old))

>> +	      return;

>> +

>> +	    if (__i < _GLIBCXX_SPIN_COUNT_2)

>> +	      __thread_relax();

>> +	    else

>> +	      __thread_yield();

>> +	  }

>> +

>> +	auto& __w = __waiters::_S_for((void*)__addr);

>> +	auto __version = __w._M_enter_wait();

>> +	while (auto __res = __pred(__old))

>> +	  {

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

>> +	      }

>> +	  }

>> +	__w._M_leave_wait();

>> +      }

>> +

>> +    template<class _Tp>

>> +      void

>> +      __atomic_notify(const _Tp* __addr, bool __all) noexcept

>> +      {

>> +	auto& __w = __waiters::_S_for((void*)__addr);

>> +	if (!__w._M_waiting())

>> +	  return;

>> +

>> +	if constexpr (__platform_wait_uses_type<_Tp>::__value)

>> +	  {

>> +	    __platform_notify((__platform_wait_t*)(void*) __addr, __all);

>> +	  }

>> +	else

>> +	  {

>> +	    __w._M_notify(__all);

>> +	  }

>> +      }

>> +  } // namespace __detail

>> +

>> +_GLIBCXX_END_NAMESPACE_VERSION

>> +} // namespace std

>> +

>> +#endif

>> +

>> diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic

>> index 40f23bdfc96..cb2308b0cdf 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/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..1d8d13621cc

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

>> --- /dev/null

>> +++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc

>> @@ -0,0 +1,57 @@

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

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

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

>> +}

Patch

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 80aeb3f8959..d195a721fd5 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -100,6 +100,7 @@  bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index eb437ad8d8d..4faaac5fb8d 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -445,6 +445,7 @@  bits_headers = \
 	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
+	${bits_srcdir}/atomic_wait.h \
 	${bits_srcdir}/atomic_futex.h \
 	${bits_srcdir}/basic_ios.h \
 	${bits_srcdir}/basic_ios.tcc \
@@ -526,6 +527,7 @@  bits_headers = \
 	${bits_srcdir}/specfun.h \
 	${bits_srcdir}/sstream.tcc \
 	${bits_srcdir}/std_abs.h \
+	${bits_srcdir}/std_condvar.h \
 	${bits_srcdir}/std_function.h \
 	${bits_srcdir}/std_mutex.h \
 	${bits_srcdir}/stl_algo.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 87fe0bd6000..b4fbe2c6eb3 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,11 @@ 
 #include <bits/atomic_lockfree_defines.h>
 #include <bits/move.h>
 
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#include <iostream>
+#endif
+
 #ifndef _GLIBCXX_ALWAYS_INLINE
 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
 #endif
@@ -134,7 +139,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
-
   // Base types for atomics.
   template<typename _IntTp>
     struct __atomic_base;
@@ -542,6 +546,35 @@  _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
+      {
+	__detail::__atomic_wait(&_M_i, __old, [__m, this](__int_type __o)
+					      {
+						return this->load(__m) == __o;
+					      });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      {
+	__detail::__atomic_notify(&_M_i, false);
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      {
+	__detail::__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 +836,35 @@  _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
+      {
+	__detail::__atomic_wait(&_M_p, __old, [__m, this](__pointer_type __o)
+					      {
+						return this->load(__m) == __o;
+					      });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      {
+	__detail::__atomic_notify(&_M_p, false);
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      {
+	__detail::__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 +953,39 @@  _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
+      {
+	__detail::__atomic_wait_ptr(__ptr, std::__addressof(__old),
+				    [=](_Tp* __o)
+				    {
+				      return load(__ptr, __m) == *__o;
+				    });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      {
+	__detail::__atomic_notify(__ptr, false);
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      {
+	__detail::__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 +1239,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 +1393,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 +1504,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 +1675,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 +1800,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_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
new file mode 100644
index 00000000000..fa2650afc39
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -0,0 +1,295 @@ 
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  namespace __detail
+  {
+    using __platform_wait_t = int;
+
+    template<class _Tp>
+      struct __platform_wait_uses_type
+      {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	enum { __value = std::is_same<typename std::remove_cv<_Tp>::type,
+				      __platform_wait_t>::value };
+#else
+	enum { __value = std::false_type::value };
+#endif
+      };
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    enum
+    {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+     __futex_private_flag = 128,
+#else
+     __futex_private_flag = 0,
+#endif
+     __futex_wait = 0,
+     __futex_wake = 1,
+     __futex_wait_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) __waiter
+    {
+      bool _M_signaled = false;
+      void* _M_t;
+      __waiter* _M_prev = nullptr;
+      __waiter* _M_next = nullptr;
+
+      __waiter(void* __t) noexcept
+      : _M_t(__t)
+      { }
+    };
+
+    struct alignas(64) __waiters
+    {
+      int32_t alignas(64) _M_ver = 0;
+      int32_t alignas(64) _M_wait = 0;
+
+      // TODO make this used only where we don't have futexes
+      using __lock_t = std::unique_lock<std::mutex>;
+      mutable __lock_t::mutex_type _M_mtx;
+
+#ifdef __GTHREAD_COND_INIT
+      mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+      __waiters() noexcept = default;
+#else
+      mutable __gthread_cond_t _M_cv;
+      __waiters() noexcept
+      {
+	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+      }
+#endif
+
+      int32_t
+      _M_enter_wait() noexcept
+      {
+	int32_t __res;
+	__atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+	__atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+	return __res;
+      }
+
+      void
+      _M_leave_wait() noexcept
+      {
+	__atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+      }
+
+      void
+      _M_do_wait(int32_t __version) const noexcept
+      {
+	int32_t __cur = 0;
+	while (__cur <= __version)
+	  {
+	    __waiters::__lock_t __l(_M_mtx);
+	    auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+	    if (__e)
+	      std::terminate();
+	    int32_t __last = __cur;
+	    __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+	    // protect if version overflows
+	    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];
+      }
+    };
+
+    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
+    }
+
+    template<class _Tp, class _Pred>
+      void
+      __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+     {
+	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	  {
+	    if (!__pred(__old))
+	      return;
+
+	    if (__i < _GLIBCXX_SPIN_COUNT_2)
+	      __thread_relax();
+	    else
+	      __thread_yield();
+	  }
+
+	auto& __w = __waiters::_S_for((void*)__addr);
+	auto __version = __w._M_enter_wait();
+	while (auto __res = __pred(__old))
+	  {
+	    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(__version);
+	      }
+	  }
+	__w._M_leave_wait();
+      }
+
+    template<class _Tp, class _Pred>
+      void
+      __atomic_wait_ptr(const _Tp* __addr, _Tp* __old, _Pred __pred) noexcept
+     {
+	for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+	  {
+	    if (!__pred(__old))
+	      return;
+
+	    if (__i < _GLIBCXX_SPIN_COUNT_2)
+	      __thread_relax();
+	    else
+	      __thread_yield();
+	  }
+
+	auto& __w = __waiters::_S_for((void*)__addr);
+	auto __version = __w._M_enter_wait();
+	while (auto __res = __pred(__old))
+	  {
+	    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(__version);
+	      }
+	  }
+	__w._M_leave_wait();
+      }
+
+    template<class _Tp>
+      void
+      __atomic_notify(const _Tp* __addr, bool __all) noexcept
+      {
+	auto& __w = __waiters::_S_for((void*)__addr);
+	if (!__w._M_waiting())
+	  return;
+
+	if constexpr (__platform_wait_uses_type<_Tp>::__value)
+	  {
+	    __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+	  }
+	else
+	  {
+	    __w._M_notify(__all);
+	  }
+      }
+  } // namespace __detail
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
+
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 40f23bdfc96..cb2308b0cdf 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/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..1d8d13621cc
--- /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..98258686945
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
@@ -0,0 +1,57 @@ 
+// { 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..e6eeebf4ab2
--- /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..fe0b8de9f3f
--- /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;
+}