[PATCH] Add C++2a synchronization support

Jonathan Wakely jwakely@redhat.com
Mon Aug 3 14:09:57 GMT 2020


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

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

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

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

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

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

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

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

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

>+      template<typename _Duration>
>+	bool
>+	__try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept
>+	{
>+	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
>+	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
>+
>+	  struct timespec __ts =
>+	  {
>+	    static_cast<std::time_t>(__s.time_since_epoch().count()),
>+	    static_cast<long>(__ns.count())
>+	  };
>+
>+	  auto __err = sem_timedwait(&_M_semaphore, &__ts);
>+	  if (__err && (errno == ETIMEDOUT))
>+	      return false;
>+	  else if (__err)
>+	      std::terminate();

I think this needs to handle both EINTR and EINVAL:

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

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

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


>+	  return true;
>+	}
>+
>+      template<typename _Clock, typename _Duration>
>+	bool
>+	try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
>+	{
>+	  if constexpr (std::is_same<__clock_t, _Clock>::value)
>+	    {
>+	      return __try_acquire_until_impl(__atime);
>+	    }
>+	  else
>+	    {
>+	      const typename _Clock::time_point __c_entry = _Clock::now();
>+	      const __clock_t __s_entry = __clock_t::now();
>+	      const auto __delta = __atime - __c_entry;
>+	      const auto __s_atime = __s_entry + __delta;
>+	      if (__try_acquire_until_impl(__s_atime))
>+		return true;
>+
>+	      // We got a timeout when measured against __clock_t but
>+	      // we need to check against the caller-supplied clock
>+	      // to tell whether we should return a timeout.
>+	      return (_Clock::now() < __atime);
>+	    }
>+	}
>+
>+      template<typename _Rep, typename _Period>
>+	_GLIBCXX_ALWAYS_INLINE bool
>+	try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
>+	{ return try_acquire_until(__clock_t::now() + __rtime); }
>+
>+      template<typename _Clock, typename _Duration>
>+	_GLIBCXX_ALWAYS_INLINE void
>+	release(ptrdiff_t __update) noexcept
>+	{
>+	  do
>+	    {
>+	      auto __err = sem_post(&_M_semaphore);
>+	      if (__err)
>+		std::terminate();
>+	    } while (--__update);
>+	}
>+
>+      private:
>+	sem_t _M_semaphore;
>+      };
>+#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+
>+    template<typename _Tp>
>+      struct __atomic_semaphore
>+      {

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

>+	explicit __atomic_semaphore(_Tp __count)

Add noexcept?

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

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

>+	      if (__old == 0)
>+		return false;
>+	      return __atomic_impl::compare_exchange_strong(&this->_M_a,
>+			__old, __old - 1,
>+			memory_order::acquire,
>+			memory_order::release);
>+	    };
>+	  auto __old = __atomic_impl::load(&_M_a, memory_order_relaxed);
>+	  __atomic_wait(&_M_a, __old, __pred);

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

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

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

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

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

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

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

Redundant condition again.

>+				&& __least_max_value <= SEM_VALUE_MAX),
>+			      __platform_semaphore<__least_max_value>,
>+			      __atomic_semaphore<ptrdiff_t>>;
>+#  else
>+  template<ptrdiff_t __least_max_value>
>+    using __semaphore_base = __atomic_semaphore<ptrdiff_t>;
>+#  endif
>+#endif
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+
>+#endif
>diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
>index a455286a784..3f18774031d 100644
>--- a/libstdc++-v3/include/std/atomic
>+++ b/libstdc++-v3/include/std/atomic
>@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     compare_exchange_strong(bool& __i1, bool __i2,
> 		    memory_order __m = memory_order_seq_cst) volatile noexcept
>     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
>+
>+#if __cplusplus > 201703L
>+    void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
>+    { _M_base.wait(__old, __m); }
>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_base.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_base.notify_all(); }
>+#endif
>   };
>
> #if __cplusplus <= 201703L
>@@ -352,6 +365,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 		     memory_order __m = memory_order_seq_cst) volatile noexcept
>       { return compare_exchange_strong(__e, __i, __m,
>                                        __cmpexch_failure_order(__m)); }
>+#if __cplusplus > 201703L
>+    void wait(_Tp __old, memory_order __m = memory_order_seq_cst) noexcept
>+    { _M_i.wait(__old, __m); }

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

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

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

>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_i.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_i.notify_all(); }
>+#endif
>+
>     };
> #undef _GLIBCXX20_INIT
>
>@@ -590,6 +616,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 					    __cmpexch_failure_order(__m));
>       }
>
>+#if __cplusplus > 201703L
>+    void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
>+    { _M_b.wait(__old, __m); }
>+
>+    // TODO add const volatile overload
>+
>+    void notify_one() const noexcept
>+    { _M_b.notify_one(); }
>+
>+    void notify_all() const noexcept
>+    { _M_b.notify_all(); }
>+#endif
>       __pointer_type
>       fetch_add(ptrdiff_t __d,
> 		memory_order __m = memory_order_seq_cst) noexcept
>@@ -1342,6 +1380,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 						     memory_order_seq_cst);
>     }
>
>+
>+#if __cplusplus > 201703L
>+  template<typename _Tp>
>+    inline void atomic_wait(const atomic<_Tp>* __a,

Newline after the return type.

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

And here.

>+				     typename std::atomic<_Tp>::value_type __old,
>+				     std::memory_order __m) noexcept
>+    { __a->wait(__old, __m); }
>+
>+  template<typename _Tp>
>+    inline void atomic_notify_one(atomic<_Tp>* __a) noexcept
>+    { __a->notify_one(); }
>+
>+  template<typename _Tp>
>+    inline void atomic_notify_all(atomic<_Tp>* __a) noexcept
>+    { __a->notify_all(); }
>+
>+#endif // C++2a
>+
>   // Function templates for atomic_integral and atomic_pointer operations only.
>   // Some operations (and, or, xor) are only available for atomic integrals,
>   // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
>diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
>new file mode 100644
>index 00000000000..aa5299d9fdd
>--- /dev/null
>+++ b/libstdc++-v3/include/std/latch
>@@ -0,0 +1,90 @@
>+// <latch> -*- C++ -*-
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.	This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.	 If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/latch
>+ *  This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_LATCH
>+#define _GLIBCXX_LATCH
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_latch 201907L
>+
>+#include <bits/atomic_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  class latch
>+  {
>+  public:
>+    static constexpr
>+    _GLIBCXX_ALWAYS_INLINE ptrdiff_t

I don't think we need _GLIBCXX_ALWAYS_INLINE here.

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

Add noexcept.

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

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

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

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

>+
>+      __semaphore_base<__least_max_value> _M_sem;

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

>+
>+    public:
>+      explicit counting_semaphore(ptrdiff_t __desired) noexcept
>+	: _M_sem(__desired)
>+      { }
>+
>+      ~counting_semaphore() = default;
>+
>+      counting_semaphore(const counting_semaphore&) = delete;
>+      counting_semaphore& operator=(const counting_semaphore&) = delete;
>+
>+      static constexpr ptrdiff_t max() noexcept
>+      { return __least_max_value; }
>+
>+      void release(ptrdiff_t __update = 1)

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

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

Same here.

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

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

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

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

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

>+	{ return _M_sem.try_acquire_until(__abs_time); }
>+    };
>+
>+ using binary_semaphore = std::counting_semaphore<1>;
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_SEMAPHORE
>diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
>index c6bde2cfbda..f09da3344f7 100644
>--- a/libstdc++-v3/include/std/version
>+++ b/libstdc++-v3/include/std/version
>@@ -189,6 +189,8 @@
> #endif
> #define __cpp_lib_type_identity 201806L
> #define __cpp_lib_unwrap_ref 201811L
>+#define __cpp_lib_semaphore 201907L
>+#define __cpp_lib_latch 201907L

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

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

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

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

>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <chrono>
>+
>+#include <testsuite_hooks.h>
>+
>+template<typename Tp>
>+Tp check_wait_notify(Tp val1, Tp val2)
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<Tp> a(val1);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(val1);
>+		  if (a.load() != val2)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  a.notify_one();
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp>
>+Tp check_atomic_wait_notify(Tp val1, Tp val2)
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  std::atomic<Tp> a(val1);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  std::atomic_wait(&a, val1);
>+		  if (a.load() != val2)
>+		    a = val1;
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(val2);
>+  std::atomic_notify_one(&a);
>+  t.join();
>+  return a.load();
>+}
>+
>+template<typename Tp>
>+struct check
>+{
>+  check()
>+  {
>+    Tp a = 0;
>+    Tp b = 42;
>+    VERIFY(check_wait_notify(a, b) == b);
>+    VERIFY(check_atomic_wait_notify(a, b) == b);
>+  }
>+};
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>new file mode 100644
>index 00000000000..2afd19a7d14
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/integrals.cc
>@@ -0,0 +1,56 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include "generic.h"
>+
>+int
>+main ()
>+{
>+  // check<bool> bb;
>+  check<char> ch;
>+  check<signed char> sch;
>+  check<unsigned char> uch;
>+  check<short> s;
>+  check<unsigned short> us;
>+  check<int> i;
>+  check<unsigned int> ui;
>+  check<long> l;
>+  check<unsigned long> ul;
>+  check<long long> ll;
>+  check<unsigned long long> ull;
>+
>+  check<wchar_t> wch;
>+  check<char8_t> ch8;
>+  check<char16_t> ch16;
>+  check<char32_t> ch32;
>+
>+  check<int8_t> i8;
>+  check<int16_t> i16;
>+  check<int32_t> i32;
>+  check<int64_t> i64;
>+
>+  check<uint8_t> u8;
>+  check<uint16_t> u16;
>+  check<uint32_t> u32;
>+  check<uint64_t> u64;
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>new file mode 100644
>index 00000000000..8531bb2e788
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/pointers.cc
>@@ -0,0 +1,59 @@
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+#include <atomic>
>+#include <thread>
>+#include <mutex>
>+#include <condition_variable>
>+#include <type_traits>
>+#include <chrono>
>+
>+#include <testsuite_hooks.h>
>+
>+int
>+main ()
>+{
>+  using namespace std::literals::chrono_literals;
>+
>+  std::mutex m;
>+  std::condition_variable cv;
>+
>+  long aa;
>+  long bb;
>+
>+  std::atomic<long*> a(nullptr);
>+  std::thread t([&]
>+		{
>+		  cv.notify_one();
>+		  a.wait(nullptr);
>+		  if (a.load() == &aa)
>+		    a.store(&bb);
>+		});
>+  std::unique_lock<std::mutex> l(m);
>+  cv.wait(l);
>+  std::this_thread::sleep_for(100ms);
>+  a.store(&aa);
>+  a.notify_one();
>+  t.join();
>+  VERIFY( a.load() == &bb);
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/1.cc b/libstdc++-v3/testsuite/30_threads/latch/1.cc
>new file mode 100644
>index 00000000000..aa203cdf525
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/1.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <latch>
>+
>+#ifndef __cpp_lib_latch
>+# error "Feature-test macro for latch missing in <latch>"
>+#elif __cpp_lib_latch!= 201907L
>+# error "Feature-test macro for latch has wrong value in <latch>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/2.cc b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>new file mode 100644
>index 00000000000..756727f33b3
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/2.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <version>
>+
>+#ifndef __cpp_lib_latch
>+# error "Feature-test macro for latch missing in <version>"
>+#elif __cpp_lib_latch != 201907L
>+# error "Feature-test macro for latch has wrong value in <version>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/latch/3.cc b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>new file mode 100644
>index 00000000000..10bb500d261
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/latch/3.cc
>@@ -0,0 +1,50 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
>+//

Just 2020.

>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+//
>+#include <latch>
>+#include <atomic>
>+#include <thread>
>+#include <testsuite_hooks.h>
>+
>+int main()
>+{
>+  std::atomic<int> a(0);
>+
>+  std::latch l(3);
>+
>+  VERIFY( !l.try_wait() );
>+
>+  auto fn = [&]
>+  {
>+    ++a;
>+    l.count_down();
>+  };
>+
>+  std::thread t0(fn);
>+  std::thread t1(fn);
>+
>+  l.arrive_and_wait();
>+  t0.join();
>+  t1.join();
>+
>+  VERIFY( l.try_wait() );
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>new file mode 100644
>index 00000000000..1bbca687fc3
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <semaphore>
>+
>+#ifndef __cpp_lib_semaphore
>+# error "Feature-test macro for semaphore missing in <semaphore>"
>+#elif __cpp_lib_semaphore != 201907L
>+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>new file mode 100644
>index 00000000000..b96b8a59c64
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
>@@ -0,0 +1,27 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <version>
>+
>+#ifndef __cpp_lib_semaphore
>+# error "Feature-test macro for semaphore missing in <version>"
>+#elif __cpp_lib_semaphore != 201907L
>+# error "Feature-test macro for semaphore has wrong value in <version>"
>+#endif
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>new file mode 100644
>index 00000000000..1ac9d261ca5
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
>@@ -0,0 +1,28 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a" }
>+// { dg-do compile { target c++2a } }
>+
>+#include <semaphore>
>+
>+int main()
>+{
>+  std::counting_semaphore<-1> sem(2);
>+  return 0;
>+}
>+// { dg-error "static assertion failed" "" {  target *-*-* } 0 }
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>new file mode 100644
>index 00000000000..d38cef86cfc
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
>@@ -0,0 +1,55 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <limits>
>+#include <cstddef>
>+#include <testsuite_hooks.h>
>+
>+void test01()
>+{
>+  std::counting_semaphore<10> s(3);
>+
>+  s.acquire();
>+  VERIFY( s.try_acquire() );
>+  VERIFY( s.try_acquire() );
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+void test02()
>+{
>+  std::binary_semaphore s(1);
>+
>+  s.acquire();
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+
>+int main()
>+{
>+  test01();
>+  test02();
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>new file mode 100644
>index 00000000000..965554a3c28
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
>@@ -0,0 +1,85 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

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

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <limits>
>+#include <cstddef>
>+#include <testsuite_hooks.h>
>+
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+void test01()
>+{
>+  // the implementation optimizes for values of least_max_t that can fit
>+  // in a futex, make sure we cover the case where least_max_t doesn't
>+  auto constexpr least_max_t = std::numeric_limits<std::ptrdiff_t>::max();
>+  std::counting_semaphore<least_max_t> s(3);
>+
>+  s.acquire();
>+  VERIFY( s.try_acquire() );
>+  VERIFY( s.try_acquire() );
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+#endif
>+
>+int main()
>+{
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+  test01();
>+#endif
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>new file mode 100644
>index 00000000000..bf99fd3cf8f
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
>@@ -0,0 +1,169 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// You should have received a copy of the GNU General Public License along
>+// with this library; see the file COPYING3.  If not see
>+// <http://www.gnu.org/licenses/>.
>+
>+// { dg-options "-std=gnu++2a -pthread" }
>+// { dg-do run { target c++2a } }
>+// { dg-require-effective-target pthread }
>+// { dg-require-gthreads "" }
>+
>+#include <semaphore>
>+#include <chrono>
>+#include <thread>
>+#include <atomic>
>+#include <testsuite_hooks.h>
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  // The implementation supports posix as an implementation strategy
>+  // make sure we cover that case
>+#define _GLIBCXX_REQUIRE_POSIX_SEMAPHORE


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

>+void test01()
>+{
>+  std::counting_semaphore<10> s(3);
>+
>+  s.acquire();
>+  VERIFY( s.try_acquire() );
>+  VERIFY( s.try_acquire() );
>+  VERIFY( !s.try_acquire() );
>+  s.release();
>+  VERIFY( s.try_acquire() );
>+}
>+
>+void test02()
>+{
>+  using namespace std::chrono_literals;
>+  std::counting_semaphore<10> s(2);
>+  s.acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s.try_acquire_for(dur) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s.try_acquire_for(dur) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test03()
>+{
>+  using namespace std::chrono_literals;
>+  std::binary_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    VERIFY( !s.try_acquire_for(dur) );
>+    b++;
>+    b.notify_one();
>+
>+    a.wait(1);
>+    VERIFY( s.try_acquire_for(dur) );
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s.acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s.release();
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+
>+void test04()
>+{
>+  using namespace std::chrono_literals;
>+  std::counting_semaphore<10> s(2);
>+  s.acquire();
>+
>+  auto const dur = 250ms;
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( s.try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff < dur );
>+  }
>+
>+  {
>+    auto const at = std::chrono::system_clock::now() + dur;
>+    auto const t0 = std::chrono::steady_clock::now();
>+    VERIFY( !s.try_acquire_until(at) );
>+    auto const diff = std::chrono::steady_clock::now() - t0;
>+    VERIFY( diff >= dur );
>+  }
>+}
>+
>+void test05()
>+{
>+  using namespace std::chrono_literals;
>+  std::binary_semaphore s(1);
>+  std::atomic<int> a(0), b(0);
>+  std::thread t([&] {
>+    a.wait(0);
>+    auto const dur = 250ms;
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( !s.try_acquire_until(at) );
>+
>+      b++;
>+      b.notify_one();
>+    }
>+
>+    a.wait(1);
>+    {
>+      auto const at = std::chrono::system_clock::now() + dur;
>+      VERIFY( s.try_acquire_until(at) );
>+    }
>+    b++;
>+    b.notify_one();
>+  });
>+  t.detach();
>+
>+  s.acquire();
>+  a++;
>+  a.notify_one();
>+  b.wait(0);
>+  s.release();
>+  a++;
>+  a.notify_one();
>+
>+  b.wait(1);
>+}
>+#endif
>+
>+int main()
>+{
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+  test01();
>+  test02();
>+  test03();
>+  test04();
>+  test05();
>+#endif
>+}
>diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>new file mode 100644
>index 00000000000..cc67c5c0bf0
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
>@@ -0,0 +1,94 @@
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.

Just 2020.

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



More information about the Gcc-patches mailing list