Hopefully less borked than the previous one, adds futex support.
----- Original Message -----
From: "Thomas Rodgers" <[email protected]>
To: [email protected], [email protected]
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" <[email protected]>
To: "Thomas Rodgers" <[email protected]>
Cc: [email protected], [email protected]
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 <[email protected]>
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