* [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<>
@ 2020-03-16 0:43 Thomas Rodgers
2020-03-17 20:25 ` Thomas Rodgers
0 siblings, 1 reply; 4+ messages in thread
From: Thomas Rodgers @ 2020-03-16 0:43 UTC (permalink / raw)
To: gcc-patches, libstdc++; +Cc: trodgers, Thomas Rodgers
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<>
2020-03-16 0:43 [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<> Thomas Rodgers
@ 2020-03-17 20:25 ` Thomas Rodgers
2020-03-24 0:09 ` Thomas Rodgers
0 siblings, 1 reply; 4+ messages in thread
From: Thomas Rodgers @ 2020-03-17 20:25 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: gcc-patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 98 bytes --]
Updated patch attached, addresses some minor issues I found after
sending the original version.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: le patch --]
[-- Type: text/x-patch, Size: 35937 bytes --]
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
[-- Attachment #3: Type: text/plain, Size: 38047 bytes --]
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;
> +}
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<>
2020-03-17 20:25 ` Thomas Rodgers
@ 2020-03-24 0:09 ` Thomas Rodgers
0 siblings, 0 replies; 4+ messages in thread
From: Thomas Rodgers @ 2020-03-24 0:09 UTC (permalink / raw)
To: Thomas Rodgers; +Cc: Thomas Rodgers, libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 120 bytes --]
Updated patch, fixes some whitespace issues along with ensuring that
libstdc++-v3/include/Makefile.in is regenerated.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-C-2a-wait-notify_one-notify_all-support-to-std-a.patch --]
[-- Type: text/x-patch, Size: 35269 bytes --]
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
[-- Attachment #3: Type: text/plain, Size: 39365 bytes --]
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;
>> +}
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<>
[not found] <516102421.8809495.1584061573691.JavaMail.zimbra@redhat.com>
@ 2020-03-13 1:06 ` Thomas Rodgers
0 siblings, 0 replies; 4+ messages in thread
From: Thomas Rodgers @ 2020-03-13 1:06 UTC (permalink / raw)
To: gcc-patches, libstdc++
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-Add-C-2a-wait-notify_one-notify_all-support-to-std-a.patch --]
[-- Type: text/x-patch; name=0001-Add-C-2a-wait-notify_one-notify_all-support-to-std-a.patch, Size: 32966 bytes --]
From f650ed07ed13c40624b72b7b4bebd967fa33f917 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/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.
* 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 | 180 ++++++++++-
libstdc++-v3/include/bits/atomic_wait.h | 295 ++++++++++++++++++
libstdc++-v3/include/std/atomic | 38 +++
.../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 | 62 ++++
.../atomic/wait_notify/integrals.cc | 56 ++++
.../29_atomics/atomic/wait_notify/pointers.cc | 59 ++++
11 files changed, 883 insertions(+), 2 deletions(-)
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..0581c41b30f 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) 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() noexcept
+ {
+ __detail::__atomic_notify(&_M_i, false);
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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() noexcept
+ {
+ __detail::__atomic_notify(&_M_p, false);
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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
@@ -860,7 +922,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Tp>
- _GLIBCXX_ALWAYS_INLINE _Tp
+ // // // // // // // // // // // // _GLIBCXX_ALWAYS_INLINE _Tp
exchange(_Tp* __ptr, _Val<_Tp> __desired, memory_order __m) noexcept
{
alignas(_Tp) unsigned char __buf[sizeof(_Tp)];
@@ -891,6 +953,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__success), int(__failure));
}
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_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(_Tp* __ptr) noexcept
+ {
+ __detail::__atomic_notify(__ptr, false);
+ }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all(_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) noexcept
+ { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() noexcept
+ { __atomic_impl::notify_one(&_M_fp); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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) noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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) noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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) noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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) noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() 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..e9401c839ce
--- /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(_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(__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(_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(__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(_Tp* __addr, bool __all) noexcept
+ {
+ auto& __w = __waiters::_S_for(__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..438a0964802 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) noexcept
+ { _M_base.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() noexcept
+ { _M_base.notify_one(); }
+
+ void notify_all() 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() noexcept
+ { _M_i.notify_one(); }
+
+ void notify_all() 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() noexcept
+ { _M_b.notify_one(); }
+
+ void notify_all() noexcept
+ { _M_b.notify_all(); }
+#endif
__pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
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..13d006d1515
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/generic.h
@@ -0,0 +1,62 @@
+// -*- 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>
+struct check
+{
+ check()
+ {
+ Tp a = 0;
+ Tp b = 42;
+ VERIFY(check_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
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-03-24 0:09 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-16 0:43 [PATCH] Add C++2a wait/notify_one/notify_all support to std::atomic<> Thomas Rodgers
2020-03-17 20:25 ` Thomas Rodgers
2020-03-24 0:09 ` Thomas Rodgers
[not found] <516102421.8809495.1584061573691.JavaMail.zimbra@redhat.com>
2020-03-13 1:06 ` Thomas Rodgers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).