Hopefully less borked than the previous one, adds futex support.

----- Original Message -----
From: "Thomas Rodgers" <trodg...@redhat.com>
To: gcc-patches@gcc.gnu.org, libstd...@gcc.gnu.org
Sent: Wednesday, February 19, 2020 7:18:36 PM
Subject: Re: [PATCH] Add c++2a binary_semaphore

Should address the previous issues, adds backoff logic.

    * include/std/semaphore: New file.
    * include/std/version (__cpp_lib_semaphore): Add feature test macro.
    * include/Makefile.am (std_headers): add semaphore.
    * include/Makefile.in: Regenerate.
    * testsuite/30_threads/semaphore/1.cc: New test.
    * testsuite/30_threads/semaphore/2.cc: New test.
    * testsuite/30_threads/semaphore/binary_semaphore.cc: New test.
    * testsuite/30_threads/semaphore/try_acquire.cc: New test.
    * testsuite/30_threads/semaphore/try_acquire_for.cc: New test.
    * testsuite/30_threads/semaphore/try_acquire_until.cc: New test.

----- Original Message -----
From: "Jonathan Wakely" <jwak...@redhat.com>
To: "Thomas Rodgers" <trodg...@redhat.com>
Cc: gcc-patches@gcc.gnu.org, libstd...@gcc.gnu.org
Sent: Tuesday, February 18, 2020 6:25:41 AM
Subject: Re: [PATCH] Add c++2a binary_semaphore

On 18/02/20 01:46 -0500, Thomas Rodgers wrote:
>This patch adds the c++2a semaphore header and binary_semaphore type. The 
>implementation is not complete, this patch is just to solicit initial feedback.

Here is some initial feedback on comments and whitespace :-)

>diff --git a/libstdc++-v3/include/Makefile.am 
>b/libstdc++-v3/include/Makefile.am
>index 89835759069..2dbb7d3a6b1 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -69,6 +69,7 @@ std_headers = \
>       ${std_srcdir}/ratio \
>       ${std_srcdir}/regex \
>       ${std_srcdir}/scoped_allocator \
>+  ${std_srcdir}/semaphore \

Indentation is borked.

>       ${std_srcdir}/set \
>       ${std_srcdir}/shared_mutex \
>       ${std_srcdir}/span \
>diff --git a/libstdc++-v3/include/std/semaphore 
>b/libstdc++-v3/include/std/semaphore
>new file mode 100644
>index 00000000000..e3e88a50eec
>--- /dev/null
>+++ b/libstdc++-v3/include/std/semaphore
>@@ -0,0 +1,131 @@
>+// <stop_token> -*- C++ -*-

Wrong header name in comment.

>+
>+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// 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/stop_token

Wrong name again.

>+ *  This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE
>+#define _GLIBCXX_SEMAPHORE
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_semaphore 201907L

We shouldn't define this until the file is complete, i.e. when it
provides binary_semaphore and counting_semaphore.

>+
>+#include <cstddef>

Is this header needed? ptrdiff_t and size_t are both defined in
<bits/c++config.h> which every header already includes.

>+#include <atomic>
>+#include <chrono>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  // TODO: replace this with a real implementation of std::binary_semaphore
>+  struct binary_semaphore
>+{

Indentation is borked here too.

>+  explicit binary_semaphore(int __d) : _M_counter(__d > 0) { }
>+
>+  static constexpr std::ptrdiff_t
>+  max() noexcept
>+  {
>+   return 1;
>+  }
>+
>+  void release() { _M_counter.fetch_add(1, memory_order::release); }
>+
>+  void acquire()
>+  {
>+   while (!_M_try_acquire())
>+     {
>+      _S_yield();
>+     }
>+  }
>+
>+  bool
>+  try_acquire() noexcept
>+  {
>+   return _M_try_acquire(1u);
>+  }
>+
>+  template<class _Rep, class _Period>
>+  bool try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
>+  {
>+   auto __abst = std::chrono::steady_clock::now() + __rel_time;
>+   return try_acquire_until(__abst);
>+  }
>+
>+  template<class _Clock, class _Duration>
>+  bool try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& 
>__abs_time)
>+  {
>+   do
>+     {
>+      if (_M_try_acquire())
>+        {
>+         return true;
>+        }
>+     } while (std::chrono::steady_clock::now() < __abs_time);
>+   return false;
>+  }
>+
>+private:
>+  static void
>+  _S_yield() noexcept
>+  {
>+#if defined __i386__ || defined __x86_64__
>+   __builtin_ia32_pause();
>+#elif defined _GLIBCXX_USE_SCHED_YIELD
>+   __gthread_yield();
>+#endif
>+  }
>+
>+  bool
>+  _M_try_acquire(unsigned __spin_ct)
>+  {
>+   int __old = 1;
>+   while (!_M_counter.compare_exchange_weak(__old, 0,
>+                                            memory_order::acquire,
>+                                            memory_order::relaxed))
>+     {
>+       if (--__spin_ct == 0)
>+         {
>+           return false;
>+         }
>+      __old = 1;
>+     }
>+   return true;
>+  }
>+
>+  static constexpr unsigned _S_spin_ct = 64u;
>+  bool
>+  _M_try_acquire()
>+  {
>+    return _M_try_acquire(1);
>+  }
>+
>+  atomic<int> _M_counter;
>+};
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_STOP_TOKEN

Wrong macro name in comment.

From aabb58f9381671aab73379e10359488dbecfe992 Mon Sep 17 00:00:00 2001
From: Thomas Rodgers <rodgert@thufir.appliantology.local>
Date: Mon, 24 Feb 2020 17:17:35 -0800
Subject: [PATCH] Add c++2a binary_semaphore

    * include/std/semaphore: New file.
    * include/std/version (__cpp_lib_semaphore): Add feature test macro.
    * include/Makefile.am (std_headers): add semaphore.
    * include/Makefile.in: Regenerate.
    * testsuite/30_threads/semaphore/1.cc: New test.
    * testsuite/30_threads/semaphore/2.cc: New test.
    * testsuite/30_threads/semaphore/binary_semaphore.cc: New test.
    * testsuite/30_threads/semaphore/try_acquire.cc: New test.
    * testsuite/30_threads/semaphore/try_acquire_for.cc: New test.
    * testsuite/30_threads/semaphore/try_acquire_until.cc: New test.
---
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   1 +
 libstdc++-v3/include/std/semaphore            | 323 ++++++++++++++++++
 libstdc++-v3/include/std/version              |   2 +
 .../testsuite/30_threads/semaphore/1.cc       |  27 ++
 .../testsuite/30_threads/semaphore/2.cc       |  27 ++
 .../30_threads/semaphore/binary_semaphore.cc  |  49 +++
 .../30_threads/semaphore/try_acquire.cc       |  36 ++
 .../30_threads/semaphore/try_acquire_for.cc   |  75 ++++
 .../30_threads/semaphore/try_acquire_until.cc |  75 ++++
 10 files changed, 616 insertions(+)
 create mode 100644 libstdc++-v3/include/std/semaphore
 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/binary_semaphore.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_until.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 89835759069..351941801ce 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -69,6 +69,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 \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 123d24bb1c6..7d856e4122e 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -414,6 +414,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 \
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
new file mode 100644
index 00000000000..18b63426bcb
--- /dev/null
+++ b/libstdc++-v3/include/std/semaphore
@@ -0,0 +1,323 @@
+//<semaphore> -*- C++ -*-
+
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.	This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+// GNU General Public License for more details.
+
+// 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
+
+#include <bits/c++config.h>
+#if defined(_GLIBCXX_HAS_GTHREADS)
+#include <bits/gthr.h>
+#endif
+
+#ifdef _GLIBCXX_USE_NANOSLEEP
+# include <cerrno>	// errno, EINTR
+# include <time.h>	// nanosleep
+#else
+# ifdef _GLIBCXX_HAVE_SLEEP
+#	 include <unistd.h>
+# elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
+#	 include <windows.h>
+# else
+#	 error "No sleep function known for this target"
+# endif
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#include <sys/time.h>
+#endif
+
+#include <atomic>
+#include <chrono>
+
+#include <iostream>
+#if __cplusplus > 201703L
+#define __cpp_lib_semaphore 201907L
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  struct binary_semaphore
+  {
+    explicit binary_semaphore(int __d) : _M_counter(__d > 0) { }
+
+    static constexpr std::ptrdiff_t
+    max() noexcept { return 1; }
+
+    void
+    release()
+    {
+       _M_counter.fetch_add(1, memory_order::release);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+       _S_futex_notify_all((int*)(void*)&_M_counter);
+#endif
+    }
+
+    void
+    acquire()
+    {
+      while (!_M_try_acquire())
+	{
+	  if (_M_try_acquire_sleep())
+	    break;
+	}
+    }
+
+    bool
+    try_acquire() noexcept
+    {
+       return _M_try_acquire_spin(1u, 0u);
+    }
+
+    template<class _Rep, class _Period>
+      bool
+      try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rel_time)
+      { return try_acquire_until(__clock_t::now()  + __rel_time); }
+
+    template<class _Clock, class _Duration>
+      bool
+      try_acquire_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time)
+      {
+	const auto __c_entry = _Clock::now();
+	const auto __s_entry = __clock_t::now();
+	const auto __delta = __abs_time -__c_entry;
+	const auto __s_atime = __s_entry + __delta;
+	bool __ret = _M_try_acquire();
+	while (!!__ret && __s_atime < __clock_t::now());
+	  {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+	    const auto __s = std::chrono::time_point_cast<std::chrono::seconds>(__s_atime);
+	    const auto __ns = std::chrono::duration_cast<std::chrono::nanoseconds>(__s_atime - __s);
+	    if (_S_futex_wait_until((int*)(void*)&_M_counter, 0,
+				    true, __s.time_since_epoch(), __ns))
+	      __ret = _M_try_acquire();
+#else
+	    __ret = _M_try_acquire_sleep()
+#endif
+	  };
+	return __ret;
+      }
+
+  private:
+    static void
+    _S_relax() noexcept
+    {
+#if defined __i386__ || defined __x86_64__
+      __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    static void
+    _S_yield() noexcept
+    {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+      __gthread_yield();
+#endif
+    }
+
+    static void
+    _S_sleep_for(std::chrono::microseconds __rtime)
+    {
+      if (__rtime <= __rtime.zero())
+	return;
+      auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
+      auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
+#ifdef _GLIBCXX_USE_NANOSLEEP
+      __gthread_time_t __ts =
+      {
+	static_cast<std::time_t>(__s.count()),
+	static_cast<long>(__ns.count())
+      };
+
+      while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
+	{ }
+#elif defined(_GLIBCXX_HAVE_SLEEP)
+      const auto __target = chrono::steady_clock::now() + __s + __ns;
+      while (true)
+	{
+	  unsigned __secs = __s.count();
+	  if (__ns.count() > 0)
+	    {
+# ifdef _GLIBCXX_HAVE_USLEEP
+	      long __us = __ns.count() / 1000;
+	      if (__us == 0)
+		__us = 1;
+	      ::usleep(__us);
+# else
+	      if (__ns.count() > 1000000 || __secs == 0)
+		++__secs; // No sub-second sleep function, so round up.
+#endif
+	    }
+
+	  if (__secs > 0)
+	    {
+	      // Sleep in a loop to handle interruption by signals:
+	      while ((__secs = ::sleep(__secs)))
+		{ }
+	    }
+	  const auto __now = chrono::steady_clock::now();
+	  if (__now >= __target)
+	    break;
+	  __s = chrono::duration_cast<chrono::seconds>(__target - __now);
+	  __ns = chrono::duration_cast<chrono::nanoseconds>(__target - (__now + __s));
+	}
+#elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
+	unsigned long __ms = __ns.count() / 1000000;
+	if (__ns.count() > 0 && __ms == 0)
+	  __ms = 1;
+	::Sleep(chrono::milliseconds(__s).count() + __ms);
+#endif
+	}
+
+
+    bool
+    _M_try_acquire_spin(unsigned __spin_ct1, unsigned __spin_ct2)
+    {
+      int __old = 1;
+      for (auto __spin = 0; __spin < __spin_ct1; ++__spin)
+	{
+	  if (_M_counter.compare_exchange_weak(__old, 0,
+					       memory_order::acquire,
+					       memory_order::relaxed))
+	    return true;
+	  __old = 1;
+	}
+
+	for (auto __spin = 0; __spin < __spin_ct2; _S_relax(), ++__spin)
+	  {
+	    if (_M_counter.compare_exchange_weak(__old, 0,
+						 memory_order::acquire,
+						 memory_order::relaxed))
+	      return true;
+	    __old = 1;
+	  }
+      return false;
+    }
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+    struct __backoff
+    {
+      int _M_rtime_us = 64;
+
+      void
+      _M_sleep()
+      {
+	_S_sleep_for(std::chrono::microseconds(_M_rtime_us));
+	auto __next_rtime_us = _M_rtime_us + (_M_rtime_us >> 2);
+	_M_rtime_us = __next_rtime_us < 1024 ? __next_rtime_us : 1024;
+      }
+    };
+#endif
+
+    bool
+    _M_try_acquire_sleep()
+    {
+      int __old = 1;
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+      _S_futex_wait_until((int*)(void*)&_M_counter,__old);
+#else
+      __backoff __b;
+      for (auto __spin = 0; ; __b._M_sleep(), ++__spin)
+	{
+	  if (_M_counter.compare_exchange_weak(__old, 0,
+					       memory_order::acquire,
+					       memory_order::relaxed))
+	    return true;
+	  __old = 1;
+	}
+#endif
+      return false;
+    }
+
+    using __clock_t = std::chrono::system_clock;
+    static constexpr unsigned _S_spin_ct1 = 16u;
+    static constexpr unsigned _S_spin_ct2 = 16u;
+
+    bool
+    _M_try_acquire()
+    {
+      return _M_try_acquire_spin(_S_spin_ct1, _S_spin_ct2);
+    }
+
+    atomic<int> _M_counter;
+
+    static const auto _S_futex_wake_op = 1u;
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+    bool
+    _S_futex_wait_until(int* __addr, int __val,
+			bool __has_timeout = false,
+			std::chrono::seconds __s = std::chrono::seconds::zero(),
+			std::chrono::nanoseconds __ns = std::chrono::nanoseconds::zero())
+    {
+      if (!__has_timeout)
+	{
+	  syscall (SYS_futex, __addr, 0, __val, nullptr);
+	  // Can't do anything about an error here except abort, so ignore it.
+	}
+      else
+	{
+	  struct timeval __tv;
+	  gettimeofday(&__tv, NULL);
+	  struct timespec __rt;
+	  __rt.tv_sec = __s.count() - __tv.tv_sec;
+	  __rt.tv_nsec = __ns.count() - __tv.tv_usec * 1000;
+	  if (__rt.tv_nsec < 0)
+	    {
+	      __rt.tv_nsec += 1000000000;
+	      --__rt.tv_sec;
+	    }
+	  if (__rt.tv_sec < 0)
+	    return false;
+
+	  if (syscall (SYS_futex, __addr, 0, __val, &__rt) == -1)
+	    {
+	      if (errno == ETIMEDOUT)
+		return false;
+	    }
+	}
+      return true;
+    }
+
+    void
+    _S_futex_notify_all(int* __addr)
+    {
+      syscall (SYS_futex, __addr, 1, INT_MAX);
+    }
+#endif // _GLIBCXX_HAVE_LINUX_FUTEX
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // _GLIBCXX_SEMAPHORE
+#endif // __cplusplus > 201703L
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index d8a97767453..6ab9d0924a7 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -188,6 +188,8 @@
 #define __cpp_lib_interpolate 201902L
 #ifdef _GLIBCXX_HAS_GTHREADS
 # define __cpp_lib_jthread 201907L
+// TODO uncomment when binary/counted_semaphore are fully implemented
+// # define __cpp_lib_semaphore 201907L
 #endif
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
new file mode 100644
index 00000000000..1bbca687fc3
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <semaphore>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <semaphore>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <semaphore>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
new file mode 100644
index 00000000000..b96b8a59c64
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <version>
+
+#ifndef __cpp_lib_semaphore
+# error "Feature-test macro for semaphore missing in <version>"
+#elif __cpp_lib_semaphore != 201907L
+# error "Feature-test macro for semaphore has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/binary_semaphore.cc b/libstdc++-v3/testsuite/30_threads/semaphore/binary_semaphore.cc
new file mode 100644
index 00000000000..661f0b0e32d
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/binary_semaphore.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+
+#include <testsuite_hooks.h>
+
+int main()
+{
+  std::binary_semaphore s(1);
+
+  auto ar = [&]()
+	    {
+	      for(auto i = 0u; i < 512; ++i)
+		{
+		  s.acquire();
+		  std::this_thread::sleep_for(std::chrono::microseconds(1));
+		  s.release();
+		}
+	    };
+
+  std::thread t(ar);
+  ar();
+
+  t.join();
+
+  return 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..295cfa9bca8
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+
+int main()
+{
+  std::binary_semaphore s(1);
+
+  s.acquire();
+  if (s.try_acquire())
+    return -1;
+  s.release();
+  if (!s.try_acquire())
+    return -1;
+  return 0;
+}
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..9e945094db8
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -0,0 +1,75 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+
+#include <iostream>
+
+int main()
+{
+  using lock_type = std::unique_lock<std::mutex>;
+
+  bool ready = false;
+  lock_type::mutex_type m;
+  std::condition_variable cv;
+
+  std::binary_semaphore s(1);
+  auto ar =[&]
+	   {
+	     s.acquire();
+	     {
+		lock_type l(m);
+		ready = true;
+	     }
+	     cv.notify_one();
+	     std::this_thread::sleep_for(std::chrono::milliseconds(500));
+	     s.release();
+	   };
+
+  std::thread t1(ar);
+  {
+    lock_type l(m, std::defer_lock);
+    cv.wait(l, [&] { return ready; });
+
+    if (s.try_acquire_for(std::chrono::milliseconds(100)))
+      return -1;
+    t1.join();
+    if (!s.try_acquire())
+      return -1;
+    s.release();
+    ready = false;
+  }
+
+  std::thread t2(ar);
+  {
+    lock_type l(m, std::defer_lock);
+    cv.wait(l, [&] { return ready; });
+    if (!s.try_acquire_for(std::chrono::milliseconds(1009)))
+      return -1;
+    t2.join();
+  }
+  return 0;
+}
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..46365ed69a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -0,0 +1,75 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <semaphore>
+#include <chrono>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+
+int main()
+{
+  using lock_type = std::unique_lock<std::mutex>;
+
+  bool ready = false;
+  lock_type::mutex_type m;
+  std::condition_variable cv;
+
+  auto abst = std::chrono::steady_clock::now();
+
+  std::binary_semaphore s(1);
+  auto ar =[&]
+	   {
+	     s.acquire();
+	     {
+		lock_type l(m);
+		ready = true;
+	     }
+	     cv.notify_one();
+	     std::this_thread::sleep_until(abst + std::chrono::milliseconds(500));
+	     s.release();
+	   };
+
+  std::thread t1(ar);
+  {
+    lock_type l(m, std::defer_lock);
+    cv.wait(l, [&] { return ready; });
+
+    if (s.try_acquire_until(abst + std::chrono::milliseconds(100)))
+      return -1;
+    t1.join();
+    if (!s.try_acquire())
+      return -1;
+    s.release();
+    ready = false;
+  }
+
+  std::thread t2(ar);
+  {
+    lock_type l(m, std::defer_lock);
+    cv.wait(l, [&] { return ready; });
+    if (!s.try_acquire_until(abst + std::chrono::milliseconds(1009)))
+      return -1;
+    t2.join();
+  }
+  return 0;
+}
-- 
2.24.1

Reply via email to