@@ -52,6 +52,7 @@ std_headers = \
${std_srcdir}/iostream \
${std_srcdir}/istream \
${std_srcdir}/iterator \
+ ${std_srcdir}/latch\
${std_srcdir}/limits \
${std_srcdir}/list \
${std_srcdir}/locale \
@@ -69,6 +70,7 @@ std_headers = \
${std_srcdir}/ratio \
${std_srcdir}/regex \
${std_srcdir}/scoped_allocator \
+ ${std_srcdir}/semaphore \
${std_srcdir}/set \
${std_srcdir}/shared_mutex \
${std_srcdir}/span \
@@ -100,6 +102,8 @@ bits_headers = \
${bits_srcdir}/allocated_ptr.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/atomic_base.h \
+ ${bits_srcdir}/atomic_wait.h \
+ ${bits_srcdir}/atomic_timed_wait.h \
${bits_srcdir}/atomic_futex.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@@ -174,6 +178,7 @@ bits_headers = \
${bits_srcdir}/regex_compiler.tcc \
${bits_srcdir}/regex_executor.h \
${bits_srcdir}/regex_executor.tcc \
+ ${bits_srcdir}/semaphore_base.h \
${bits_srcdir}/shared_ptr.h \
${bits_srcdir}/shared_ptr_atomic.h \
${bits_srcdir}/shared_ptr_base.h \
@@ -397,6 +397,7 @@ std_headers = \
${std_srcdir}/iostream \
${std_srcdir}/istream \
${std_srcdir}/iterator \
+ ${std_srcdir}/latch\
${std_srcdir}/limits \
${std_srcdir}/list \
${std_srcdir}/locale \
@@ -414,6 +415,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 \
@@ -445,6 +447,8 @@ bits_headers = \
${bits_srcdir}/allocated_ptr.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/atomic_base.h \
+ ${bits_srcdir}/atomic_wait.h \
+ ${bits_srcdir}/atomic_timed_wait.h \
${bits_srcdir}/atomic_futex.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@@ -519,6 +523,7 @@ bits_headers = \
${bits_srcdir}/regex_compiler.tcc \
${bits_srcdir}/regex_executor.h \
${bits_srcdir}/regex_executor.tcc \
+ ${bits_srcdir}/semaphore_base.h \
${bits_srcdir}/shared_ptr.h \
${bits_srcdir}/shared_ptr_atomic.h \
${bits_srcdir}/shared_ptr_base.h \
@@ -37,6 +37,10 @@
#include <bits/atomic_lockfree_defines.h>
#include <bits/move.h>
+#if __cplusplus > 201703L
+#include <bits/atomic_wait.h>
+#endif
+
#ifndef _GLIBCXX_ALWAYS_INLINE
#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
@@ -134,7 +138,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
-
// Base types for atomics.
template<typename _IntTp>
struct __atomic_base;
@@ -562,6 +565,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__int_type __old,
+ memory_order __m = memory_order_seq_cst) const noexcept
+ {
+ std::__atomic_wait(&_M_i, __old,
+ [__m, this, __old]()
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_i, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_i, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __int_type
fetch_add(__int_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -823,6 +851,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__m1), int(__m2));
}
+#if __cplusplus > 201703L
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(&_M_p, __old,
+ [__m, this, __old]()
+ { return this->load(__m) != __old; });
+ }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { std::__atomic_notify(&_M_p, false); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { std::__atomic_notify(&_M_p, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
_GLIBCXX_ALWAYS_INLINE __pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -911,6 +963,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int(__success), int(__failure));
}
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(const _Tp* __ptr, _Val<_Tp> __old, memory_order __m = memory_order_seq_cst) noexcept
+ {
+ std::__atomic_wait(__ptr, __old,
+ [=]() { return load(__ptr, __m) == __old; });
+ }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, false); }
+
+ // TODO add const volatile overload
+
+ template<typename _Tp>
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all(const _Tp* __ptr) noexcept
+ { std::__atomic_notify(__ptr, true); }
+
+ // TODO add const volatile overload
+#endif // C++2a
+
template<typename _Tp>
_GLIBCXX_ALWAYS_INLINE _Tp
fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
@@ -1164,6 +1242,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(&_M_fp, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(&_M_fp); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(&_M_fp); }
+
+ // TODO add const volatile overload
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1301,6 +1396,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
private:
_Tp* _M_ptr;
};
@@ -1396,6 +1507,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1551,6 +1678,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
value_type
fetch_add(value_type __i,
memory_order __m = memory_order_seq_cst) const noexcept
@@ -1660,6 +1803,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__order));
}
+ _GLIBCXX_ALWAYS_INLINE void
+ wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { __atomic_impl::wait(_M_ptr, __old, __m); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_one() const noexcept
+ { __atomic_impl::notify_one(_M_ptr); }
+
+ // TODO add const volatile overload
+
+ _GLIBCXX_ALWAYS_INLINE void
+ notify_all() const noexcept
+ { __atomic_impl::notify_all(_M_ptr); }
+
_GLIBCXX_ALWAYS_INLINE value_type
fetch_add(difference_type __d,
memory_order __m = memory_order_seq_cst) const noexcept
new file mode 100644
@@ -0,0 +1,282 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_timed_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
+#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/atomic_wait.h>
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <sys/time.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ enum class __atomic_wait_status { __no_timeout, __timeout };
+
+ namespace __detail
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ enum
+ {
+ __futex_wait_bitset_private = __futex_wait_bitset | __futex_private_flag,
+ __futex_wake_bitset_private = __futex_wake_bitset | __futex_private_flag,
+ __futex_bitset_match_any = 0xffffffff
+ };
+
+ using __platform_wait_clock_t = chrono::steady_clock;
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until_impl(__platform_wait_t* __addr, __platform_wait_t __val,
+ const chrono::time_point<__platform_wait_clock_t, _Duration>& __atime) noexcept
+ {
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ struct timespec __rt =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ auto __e = syscall (SYS_futex, __addr, __futex_wait_bitset_private, __val, &__rt,
+ nullptr, __futex_bitset_match_any);
+ if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
+ std::terminate();
+ return (__platform_wait_clock_t::now() < __atime)
+ ? __atomic_wait_status::__no_timeout : __atomic_wait_status::__timeout;
+ }
+
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+ if constexpr (std::is_same_v<__platform_wait_clock_t, _Clock>)
+ {
+ return __platform_wait_until_impl(__addr, __val, __atime);
+ }
+ else
+ {
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __platform_wait_clock_t::time_point __s_entry =
+ __platform_wait_clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (__platform_wait_until_impl(__addr, __val, __s_atime) == __atomic_wait_status::__no_timeout)
+ return __atomic_wait_status::__no_timeout;
+
+ // 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.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::__no_timeout;
+ return __atomic_wait_status::__timeout;
+ }
+ }
+#endif
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<mutex>& __lock,
+ const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
+ {
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ __gthread_time_t __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
+ CLOCK_MONOTONIC,
+ &__ts);
+ return (chrono::steady_clock::now() < __atime)
+ ? __atomic_wait_status::__no_timeout : __atomic_wait_status::__timeout;
+ }
+#endif
+
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+ {
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ __gthread_time_t __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
+ &__ts);
+ return (chrono::system_clock::now() < __atime)
+ ? __atomic_wait_status::__no_timeout
+ : __atomic_wait_status::__timeout;
+ }
+
+ // return true if timeout
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until(__gthread_cond_t* __cv,
+ unique_lock<std::mutex>& __lock,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ using __clock_t = chrono::steady_clock;
+#else
+ using __clock_t = chrono::system_clock;
+#endif
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (__cond_wait_until_impl(__cv, __lock, __s_atime))
+ return __atomic_wait_status::__no_timeout;
+ // 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.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::__no_timeout;
+ return __atomic_wait_status::__timeout;
+ }
+
+ struct __timed_waiters : __waiters
+ {
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ _M_do_wait_until(__platform_wait_t __version,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ return __platform_wait_until(&_M_ver, __version, __atime);
+#else
+ __platform_wait_t __cur = 0;
+ __waiters::__lock_t __l(_M_mtx);
+ while (__cur <= __version)
+ {
+ if (__cond_wait_until(&_M_cv, __l, __atime) == __atomic_wait_status::__timeout)
+ return __atomic_wait_status::__timeout;
+
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+ return __atomic_wait_status::__no_timeout;
+#endif
+ }
+
+ static __timed_waiters&
+ _S_timed_for(void* __t)
+ {
+ static_assert(sizeof(__timed_waiters) == sizeof(__waiters));
+ return (__timed_waiters&) __waiters::_S_for(__t);
+ }
+ };
+ } // namespace __detail
+
+ template<typename _Tp, typename _Pred,
+ typename _Clock, typename _Duration>
+ bool
+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::time_point<_Clock, _Duration>& __atime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
+ auto __version = __w._M_enter_wait();
+ do
+ {
+ __atomic_wait_status __res;
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
+ __old,
+ __atime);
+ }
+ else
+ {
+ __res = __w._M_do_wait_until(__version, __atime);
+ }
+ if (__res == __atomic_wait_status::__timeout)
+ return false;
+ }
+ while (!__pred() && __atime < _Clock::now());
+ __w._M_leave_wait();
+
+ // if timed out, return false
+ return (_Clock::now() < __atime);
+ }
+
+ template<typename _Tp, typename _Pred,
+ typename _Rep, typename _Period>
+ bool
+ __atomic_wait_for(const _Tp* __addr, _Tp __old, _Pred __pred,
+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ using namespace __detail;
+
+ if (std::__atomic_spin(__pred))
+ return true;
+
+ if (!__rtime.count())
+ return false; // no rtime supplied, and spin did not acquire
+
+ using __dur = chrono::steady_clock::duration;
+ auto __reltime = chrono::duration_cast<__dur>(__rtime);
+ if (__reltime < __rtime)
+ ++__reltime;
+
+
+ return __atomic_wait_until(__addr, __old, std::move(__pred),
+ chrono::steady_clock::now() + __reltime);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
new file mode 100644
@@ -0,0 +1,291 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/atomic_wait.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{atomic}
+ */
+
+#ifndef _GLIBCXX_ATOMIC_WAIT_H
+#define _GLIBCXX_ATOMIC_WAIT_H 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <bits/functional_hash.h>
+#include <bits/gthr.h>
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/numeric_traits.h>
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <climits>
+#include <unistd.h>
+#include <syscall.h>
+#endif
+
+#define _GLIBCXX_SPIN_COUNT_1 16
+#define _GLIBCXX_SPIN_COUNT_2 12
+
+// TODO get this from Autoconf
+#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __detail
+ {
+ using __platform_wait_t = int;
+
+ inline constexpr
+ auto __platform_wait_max_value =
+ __gnu_cxx::__numeric_traits<__platform_wait_t>::__max;
+
+ template<typename _Tp>
+ inline constexpr bool __platform_wait_uses_type
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ = is_same_v<remove_cv_t<_Tp>, __platform_wait_t>;
+#else
+ = false;
+#endif
+
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ enum
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
+ __futex_private_flag = 128,
+#else
+ __futex_private_flag = 0,
+#endif
+ __futex_wait = 0,
+ __futex_wake = 1,
+ __futex_wait_bitset = 9,
+ __futex_wake_bitset = 10,
+ __futex_wait_private = __futex_wait | __futex_private_flag,
+ __futex_wake_private = __futex_wake | __futex_private_flag
+ };
+
+ void
+ __platform_wait(__platform_wait_t* __addr, __platform_wait_t __val) noexcept
+ {
+ auto __e = syscall (SYS_futex, __addr, __futex_wait_private, __val, nullptr);
+ if (__e && !(errno == EINTR || errno == EAGAIN))
+ std::terminate();
+ }
+
+ void
+ __platform_notify(__platform_wait_t* __addr, bool __all) noexcept
+ {
+ syscall (SYS_futex, __addr, __futex_wake_private, __all ? INT_MAX : 1);
+ }
+#endif
+
+ struct __waiters
+ {
+ __platform_wait_t alignas(64) _M_ver = 0;
+ __platform_wait_t alignas(64) _M_wait = 0;
+
+#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
+ using __lock_t = std::unique_lock<std::mutex>;
+ mutable __lock_t::mutex_type _M_mtx;
+
+# ifdef __GTHREAD_COND_INIT
+ mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
+ __waiters() noexcept = default;
+# else
+ mutable __gthread_cond_t _M_cv;
+ __waiters() noexcept
+ {
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+ }
+# endif
+#endif
+
+ __platform_wait_t
+ _M_enter_wait() noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_ver, &__res, __ATOMIC_ACQUIRE);
+ __atomic_fetch_add(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ return __res;
+ }
+
+ void
+ _M_leave_wait() noexcept
+ {
+ __atomic_fetch_sub(&_M_wait, 1, __ATOMIC_ACQ_REL);
+ }
+
+ void
+ _M_do_wait(__platform_wait_t __version) noexcept
+ {
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_wait(&_M_ver, __version);
+#else
+ __platform_wait_t __cur = 0;
+ while (__cur <= __version)
+ {
+ __waiters::__lock_t __l(_M_mtx);
+ auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
+ if (__e)
+ std::terminate();
+ __platform_wait_t __last = __cur;
+ __atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
+ if (__cur < __last)
+ break; // break the loop if version overflows
+ }
+#endif
+ }
+
+ __platform_wait_t
+ _M_waiting() const noexcept
+ {
+ __platform_wait_t __res;
+ __atomic_load(&_M_wait, &__res, __ATOMIC_ACQUIRE);
+ return __res;
+ }
+
+ void
+ _M_notify(bool __all) noexcept
+ {
+ __atomic_fetch_add(&_M_ver, 1, __ATOMIC_ACQ_REL);
+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+ __platform_notify(&_M_ver, __all);
+#else
+ auto __e = __gthread_cond_broadcast(&_M_cv);
+ if (__e)
+ __throw_system_error(__e);
+#endif
+ }
+
+ static __waiters&
+ _S_for(void* __t)
+ {
+ const unsigned char __mask = 0xf;
+ static __waiters __w[__mask + 1];
+
+ auto __key = _Hash_impl::hash(__t) & __mask;
+ return __w[__key];
+ }
+ };
+
+ struct __waiter
+ {
+ __waiters& _M_w;
+ __platform_wait_t _M_version;
+
+ template<typename _Tp>
+ __waiter(const _Tp* __addr) noexcept
+ : _M_w(__waiters::_S_for((void*) __addr))
+ , _M_version(_M_w._M_enter_wait())
+ { }
+
+ ~__waiter()
+ { _M_w._M_leave_wait(); }
+
+ void _M_do_wait() noexcept
+ { _M_w._M_do_wait(_M_version); }
+ };
+
+ void
+ __thread_relax() noexcept
+ {
+#if defined __i386__ || defined __x86_64__
+ __builtin_ia32_pause();
+#elif defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ void
+ __thread_yield() noexcept
+ {
+#if defined _GLIBCXX_USE_SCHED_YIELD
+ __gthread_yield();
+#endif
+ }
+
+ } // namespace __detail
+
+ template<typename _Pred>
+ bool
+ __atomic_spin(_Pred __pred) noexcept
+ {
+ for (auto __i = 0; __i < _GLIBCXX_SPIN_COUNT_1; ++__i)
+ {
+ if (__pred())
+ return true;
+
+ if (__i < _GLIBCXX_SPIN_COUNT_2)
+ __detail::__thread_relax();
+ else
+ __detail::__thread_yield();
+ }
+ return false;
+ }
+
+ template<typename _Tp, typename _Pred>
+ void
+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
+ {
+ using namespace __detail;
+ if (__atomic_spin(__pred))
+ return;
+
+ __waiter __w(__addr);
+ while (!__pred())
+ {
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_wait((__platform_wait_t*)(void*) __addr, __old);
+ }
+ else
+ {
+ // TODO support timed backoff when this can be moved into the lib
+ __w._M_do_wait();
+ }
+ }
+ }
+
+ template<typename _Tp>
+ void
+ __atomic_notify(const _Tp* __addr, bool __all) noexcept
+ {
+ using namespace __detail;
+ auto& __w = __waiters::_S_for((void*)__addr);
+ if (!__w._M_waiting())
+ return;
+
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ __platform_notify((__platform_wait_t*)(void*) __addr, __all);
+ }
+ else
+ {
+ __w._M_notify(__all);
+ }
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif
new file mode 100644
@@ -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
+ {
+ 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();
+ }
+
+ ~__platform_semaphore()
+ {
+ auto __e = sem_destroy(&_M_semaphore);
+ if (__e)
+ std::terminate();
+ }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ acquire() noexcept
+ {
+ auto __err = sem_wait(&_M_semaphore);
+ if (__err)
+ std::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();
+ 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
+ {
+ explicit __atomic_semaphore(_Tp __count)
+ : _M_a(__count)
+ { }
+
+ _GLIBCXX_ALWAYS_INLINE void
+ acquire() 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);
+ __atomic_wait(&_M_a, __old, __pred);
+ }
+
+ 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
+ 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
+ && __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
+ && __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
@@ -163,6 +163,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
compare_exchange_strong(bool& __i1, bool __i2,
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); }
+
+#if __cplusplus > 201703L
+ void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept
+ { _M_base.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_base.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_base.notify_all(); }
+#endif
};
#if __cplusplus <= 201703L
@@ -352,6 +365,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order __m = memory_order_seq_cst) volatile noexcept
{ return compare_exchange_strong(__e, __i, __m,
__cmpexch_failure_order(__m)); }
+#if __cplusplus > 201703L
+ void wait(_Tp __old, memory_order __m = memory_order_seq_cst) noexcept
+ { _M_i.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_i.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_i.notify_all(); }
+#endif
+
};
#undef _GLIBCXX20_INIT
@@ -590,6 +616,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__cmpexch_failure_order(__m));
}
+#if __cplusplus > 201703L
+ void wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept
+ { _M_b.wait(__old, __m); }
+
+ // TODO add const volatile overload
+
+ void notify_one() const noexcept
+ { _M_b.notify_one(); }
+
+ void notify_all() const noexcept
+ { _M_b.notify_all(); }
+#endif
__pointer_type
fetch_add(ptrdiff_t __d,
memory_order __m = memory_order_seq_cst) noexcept
@@ -1342,6 +1380,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
memory_order_seq_cst);
}
+
+#if __cplusplus > 201703L
+ template<typename _Tp>
+ inline void atomic_wait(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old) noexcept
+ { __a->wait(__old); }
+
+ template<typename _Tp>
+ inline void atomic_wait_explicit(const atomic<_Tp>* __a,
+ typename std::atomic<_Tp>::value_type __old,
+ std::memory_order __m) noexcept
+ { __a->wait(__old, __m); }
+
+ template<typename _Tp>
+ inline void atomic_notify_one(atomic<_Tp>* __a) noexcept
+ { __a->notify_one(); }
+
+ template<typename _Tp>
+ inline void atomic_notify_all(atomic<_Tp>* __a) noexcept
+ { __a->notify_all(); }
+
+#endif // C++2a
+
// Function templates for atomic_integral and atomic_pointer operations only.
// Some operations (and, or, xor) are only available for atomic integrals,
// which is implemented by taking a parameter of type __atomic_base<_ITp>*.
new file mode 100644
@@ -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
+ max() noexcept
+ { return __gnu_cxx::__numeric_traits<ptrdiff_t>::__max; }
+
+ constexpr explicit latch(ptrdiff_t __expected) : _M_a(__expected) { }
+
+ ~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);
+ 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
new file mode 100644
@@ -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, "");
+
+ __semaphore_base<__least_max_value> _M_sem;
+
+ 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)
+ { _M_sem.release(__update); }
+
+ void acquire()
+ { _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)
+ { 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)
+ { 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
@@ -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
#if _GLIBCXX_HOSTED
#undef __cpp_lib_array_constexpr
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -0,0 +1,88 @@
+// -*- C++ -*- header.
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <atomic>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+
+#include <testsuite_hooks.h>
+
+template<typename Tp>
+Tp check_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ a.wait(val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ a.notify_one();
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+Tp check_atomic_wait_notify(Tp val1, Tp val2)
+{
+ using namespace std::literals::chrono_literals;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ std::atomic<Tp> a(val1);
+ std::thread t([&]
+ {
+ cv.notify_one();
+ std::atomic_wait(&a, val1);
+ if (a.load() != val2)
+ a = val1;
+ });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l);
+ std::this_thread::sleep_for(100ms);
+ a.store(val2);
+ std::atomic_notify_one(&a);
+ t.join();
+ return a.load();
+}
+
+template<typename Tp>
+struct check
+{
+ check()
+ {
+ Tp a = 0;
+ Tp b = 42;
+ VERIFY(check_wait_notify(a, b) == b);
+ VERIFY(check_atomic_wait_notify(a, b) == b);
+ }
+};
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -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_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
new file mode 100644
@@ -0,0 +1,50 @@
+// 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 <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() );
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,28 @@
+// 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 <semaphore>
+
+int main()
+{
+ std::counting_semaphore<-1> sem(2);
+ return 0;
+}
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
new file mode 100644
@@ -0,0 +1,55 @@
+// 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 <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();
+}
new file mode 100644
@@ -0,0 +1,85 @@
+// 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 <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();
+}
new file mode 100644
@@ -0,0 +1,51 @@
+// 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 <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
+}
new file mode 100644
@@ -0,0 +1,169 @@
+// 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 <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
+
+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
+}
new file mode 100644
@@ -0,0 +1,94 @@
+// 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 <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();
+}