On 11/09/20 16:58 -0700, Thomas Rodgers wrote:
From: Thomas Rodgers <trodg...@redhat.com>

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

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

libstdc++-v3/ChangeLog:

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

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c9df9a9d6c6..9b5b6ed0005 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -52,6 +52,7 @@ std_headers = \
        ${std_srcdir}/iostream \
        ${std_srcdir}/istream \
        ${std_srcdir}/iterator \
+       ${std_srcdir}/latch \
        ${std_srcdir}/limits \
        ${std_srcdir}/list \
        ${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
        ${std_srcdir}/ratio \
        ${std_srcdir}/regex \
        ${std_srcdir}/scoped_allocator \
+       ${std_srcdir}/semaphore \
        ${std_srcdir}/set \
        ${std_srcdir}/shared_mutex \
        ${std_srcdir}/span \
@@ -101,6 +103,8 @@ bits_headers = \
        ${bits_srcdir}/allocated_ptr.h \
        ${bits_srcdir}/allocator.h \
        ${bits_srcdir}/atomic_base.h \
+       ${bits_srcdir}/atomic_wait.h \
+       ${bits_srcdir}/atomic_timed_wait.h \
        ${bits_srcdir}/atomic_futex.h \
        ${bits_srcdir}/basic_ios.h \
        ${bits_srcdir}/basic_ios.tcc \
@@ -175,6 +179,7 @@ bits_headers = \
        ${bits_srcdir}/regex_compiler.tcc \
        ${bits_srcdir}/regex_executor.h \
        ${bits_srcdir}/regex_executor.tcc \
+       ${bits_srcdir}/semaphore_base.h \
        ${bits_srcdir}/shared_ptr.h \
        ${bits_srcdir}/shared_ptr_atomic.h \
        ${bits_srcdir}/shared_ptr_base.h \
diff --git a/libstdc++-v3/include/bits/atomic_base.h 
b/libstdc++-v3/include/bits/atomic_base.h
index 2cdd2bd6cae..dd4db926592 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -37,6 +37,10 @@
#include <bits/atomic_lockfree_defines.h>
#include <bits/move.h>

+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
#ifndef _GLIBCXX_ALWAYS_INLINE
#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      return __ret;
    }

-
  // Base types for atomics.
  template<typename _IntTp>
    struct __atomic_base;
@@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      __atomic_load(&_M_i, &__v, int(__m));
      return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
    }
+
+    _GLIBCXX_ALWAYS_INLINE void
+    wait(bool __old,
+       memory_order __m = memory_order_seq_cst) const noexcept
+    {
+      std::__atomic_wait(&_M_i, __old,
+                        [__m, this, __old]()
+                        { return this->test(__m) != __old; });
+    }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_one() const noexcept
+    { std::__atomic_notify(&_M_i, false); }
+
+    // TODO add const volatile overload
+
+    _GLIBCXX_ALWAYS_INLINE void
+    notify_all() const noexcept
+    { std::__atomic_notify(&_M_i, true); }
+
+    // TODO add const volatile overload
#endif // C++20

    _GLIBCXX_ALWAYS_INLINE void
@@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                       __cmpexch_failure_order(__m));
      }

+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__int_type __old,
+         memory_order __m = memory_order_seq_cst) const noexcept
+      {
+       std::__atomic_wait(&_M_i, __old,
+                          [__m, this, __old]
+                          { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_i, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_i, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
      _GLIBCXX_ALWAYS_INLINE __int_type
      fetch_add(__int_type __i,
                memory_order __m = memory_order_seq_cst) noexcept
@@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                           int(__m1), int(__m2));
      }

+#if __cplusplus > 201703L
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(__pointer_type __old,
+          memory_order __m = memory_order_seq_cst) noexcept
+      {
+       std::__atomic_wait(&_M_p, __old,
+                     [__m, this, __old]()
+                     { return this->load(__m) != __old; });
+      }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { std::__atomic_notify(&_M_p, false); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { std::__atomic_notify(&_M_p, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
      _GLIBCXX_ALWAYS_INLINE __pointer_type
      fetch_add(ptrdiff_t __d,
                memory_order __m = memory_order_seq_cst) noexcept
@@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                         int(__success), int(__failure));
      }

+#if __cplusplus > 201703L
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      wait(const _Tp* __ptr, _Val<_Tp> __old,
+          memory_order __m = memory_order_seq_cst) noexcept
+      {
+       std::__atomic_wait(__ptr, __old,
+           [=]() { return load(__ptr, __m) == __old; });
+      }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, false); }
+
+      // TODO add const volatile overload
+
+    template<typename _Tp>
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all(const _Tp* __ptr) noexcept
+      { std::__atomic_notify(__ptr, true); }
+
+      // TODO add const volatile overload
+#endif // C++2a
+
    template<typename _Tp>
      _GLIBCXX_ALWAYS_INLINE _Tp
      fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                       __cmpexch_failure_order(__order));
      }

+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(&_M_fp); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(&_M_fp); }
+
+      // TODO add const volatile overload
+
      value_type
      fetch_add(value_type __i,
                memory_order __m = memory_order_seq_cst) noexcept
@@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                       __cmpexch_failure_order(__order));
      }

+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
    private:
      _Tp* _M_ptr;
    };
@@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                       __cmpexch_failure_order(__order));
      }

+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
      value_type
      fetch_add(value_type __i,
                memory_order __m = memory_order_seq_cst) const noexcept
@@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                       __cmpexch_failure_order(__order));
      }

+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
      value_type
      fetch_add(value_type __i,
                memory_order __m = memory_order_seq_cst) const noexcept
@@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                       __cmpexch_failure_order(__order));
      }

+      _GLIBCXX_ALWAYS_INLINE void
+      wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+      { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_one() const noexcept
+      { __atomic_impl::notify_one(_M_ptr); }
+
+      // TODO add const volatile overload
+
+      _GLIBCXX_ALWAYS_INLINE void
+      notify_all() const noexcept
+      { __atomic_impl::notify_all(_M_ptr); }
+
+      // TODO add const volatile overload
+
      _GLIBCXX_ALWAYS_INLINE value_type
      fetch_add(difference_type __d,
                memory_order __m = memory_order_seq_cst) const noexcept
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h 
b/libstdc++-v3/include/bits/atomic_timed_wait.h
new file mode 100644
index 00000000000..2f57356b366
--- /dev/null
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -0,0 +1,281 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class __atomic_wait_status { no_timeout, timeout };
+
+  namespace __detail
+  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    using __platform_wait_clock_t = chrono::steady_clock;
+
+    template<typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until_impl(__platform_wait_t* __addr,
+                                __platform_wait_t __val,
+                                const 
chrono::time_point<__platform_wait_clock_t,
+                                                         _Duration>& __atime) 
noexcept
+      {
+       auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+       auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+       struct timespec __rt =
+       {
+         static_cast<std::time_t>(__s.time_since_epoch().count()),
+         static_cast<long>(__ns.count())
+       };
+
+       auto __e = syscall (SYS_futex, __addr,
+                             
static_cast<int>(__futex_wait_flags::__wait_bitset_private),
+                             __val, &__rt, nullptr,
+                             
static_cast<int>(__futex_wait_flags::__bitset_match_any));
+       if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+           std::terminate();
+       return (__platform_wait_clock_t::now() < __atime)
+              ? __atomic_wait_status::no_timeout : 
__atomic_wait_status::timeout;
+      }
+
+    template<typename _Clock, typename _Duration>
+      __atomic_wait_status
+      __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+                           const chrono::time_point<_Clock, _Duration>& 
__atime)
+      {
+       if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)

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

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

Reply via email to