libstdc++: Add C++2a synchronization support
Add support for - * atomic_flag::wait/notify_one/notify_all * atomic::wait/notify_one/notify_all * counting_semaphore * binary_semaphore * latch libstdc++-v3/ChangeLog: * include/Makefile.am (bits_headers): Add new header. * include/Makefile.in: Regenerate. * include/bits/atomic_base.h (__atomic_flag::wait): Define. (__atomic_flag::notify_one): Likewise. (__atomic_flag::notify_all): Likewise. (__atomic_base<_Itp>::wait): Likewise. (__atomic_base<_Itp>::notify_one): Likewise. (__atomic_base<_Itp>::notify_all): Likewise. (__atomic_base<_Ptp*>::wait): Likewise. (__atomic_base<_Ptp*>::notify_one): Likewise. (__atomic_base<_Ptp*>::notify_all): Likewise. (__atomic_impl::wait): Likewise. (__atomic_impl::notify_one): Likewise. (__atomic_impl::notify_all): Likewise. (__atomic_float<_Fp>::wait): Likewise. (__atomic_float<_Fp>::notify_one): Likewise. (__atomic_float<_Fp>::notify_all): Likewise. (__atomic_ref<_Tp>::wait): Likewise. (__atomic_ref<_Tp>::notify_one): Likewise. (__atomic_ref<_Tp>::notify_all): Likewise. (atomic_wait<_Tp>): Likewise. (atomic_wait_explicit<_Tp>): Likewise. (atomic_notify_one<_Tp>): Likewise. (atomic_notify_all<_Tp>): Likewise. * include/bits/atomic_wait.h: New file. * include/bits/atomic_timed_wait.h: New file. * include/bits/semaphore_base.h: New file. * include/std/atomic (atomic<bool>::wait): Define. (atomic<bool>::wait_one): Likewise. (atomic<bool>::wait_all): Likewise. (atomic<_Tp>::wait): Likewise. (atomic<_Tp>::wait_one): Likewise. (atomic<_Tp>::wait_all): Likewise. (atomic<_Tp*>::wait): Likewise. (atomic<_Tp*>::wait_one): Likewise. (atomic<_Tp*>::wait_all): Likewise. * include/std/latch: New file. * include/std/semaphore: New file. * include/std/version: Add __cpp_lib_semaphore and __cpp_lib_latch defines. * testsuite/29_atomics/atomic/wait_notify/bool.cc: New test. * testsuite/29_atomics/atomic/wait_notify/pointers.cc: Likewise. * testsuite/29_atomics/atomic/wait_notify/generic.cc: Liekwise. * testsuite/29_atomics/atomic_flag/wait_notify/1.cc: Likewise. * testsuite/29_atomics/atomic_float/wait_notify.cc: Likewise. * testsuite/29_atomics/atomic_integral/wait_notify.cc: Likewise. * testsuite/29_atomics/atomic_ref/wait_notify.cc: Likewise. * testsuite/30_threads/semaphore/1.cc: New test. * testsuite/30_threads/semaphore/2.cc: Likewise. * testsuite/30_threads/semaphore/least_max_value_neg.cc: Likewise. * testsuite/30_threads/semaphore/try_acquire.cc: Likewise. * testsuite/30_threads/semaphore/try_acquire_for.cc: Likewise. * testsuite/30_threads/semaphore/try_acquire_posix.cc: Likewise. * testsuite/30_threads/semaphore/try_acquire_until.cc: Likewise. * testsuite/30_threads/latch/1.cc: New test. * testsuite/30_threads/latch/2.cc: New test. * testsuite/30_threads/latch/3.cc: New test. * testsuite/util/atomic/wait_notify_util.h: New File.
This commit is contained in:
parent
89d9c634dc
commit
83a1beee27
28 changed files with 2506 additions and 1 deletions
|
@ -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 \
|
||||
|
@ -103,6 +105,8 @@ bits_headers = \
|
|||
${bits_srcdir}/allocator.h \
|
||||
${bits_srcdir}/atomic_base.h \
|
||||
${bits_srcdir}/atomic_futex.h \
|
||||
${bits_srcdir}/atomic_timed_wait.h \
|
||||
${bits_srcdir}/atomic_wait.h \
|
||||
${bits_srcdir}/basic_ios.h \
|
||||
${bits_srcdir}/basic_ios.tcc \
|
||||
${bits_srcdir}/basic_string.h \
|
||||
|
@ -178,6 +182,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 \
|
||||
|
|
|
@ -398,6 +398,7 @@ std_headers = \
|
|||
${std_srcdir}/iostream \
|
||||
${std_srcdir}/istream \
|
||||
${std_srcdir}/iterator \
|
||||
${std_srcdir}/latch \
|
||||
${std_srcdir}/limits \
|
||||
${std_srcdir}/list \
|
||||
${std_srcdir}/locale \
|
||||
|
@ -415,6 +416,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 \
|
||||
|
@ -449,6 +451,8 @@ bits_headers = \
|
|||
${bits_srcdir}/allocator.h \
|
||||
${bits_srcdir}/atomic_base.h \
|
||||
${bits_srcdir}/atomic_futex.h \
|
||||
${bits_srcdir}/atomic_timed_wait.h \
|
||||
${bits_srcdir}/atomic_wait.h \
|
||||
${bits_srcdir}/basic_ios.h \
|
||||
${bits_srcdir}/basic_ios.tcc \
|
||||
${bits_srcdir}/basic_string.h \
|
||||
|
@ -524,6 +528,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;
|
||||
|
@ -226,6 +229,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__atomic_load(&_M_i, &__v, int(__m));
|
||||
return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(bool __old,
|
||||
memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{
|
||||
std::__atomic_wait(&_M_i, __old,
|
||||
[__m, this, __old]()
|
||||
{ return this->test(__m) != __old; });
|
||||
}
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ std::__atomic_notify(&_M_i, false); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ std::__atomic_notify(&_M_i, true); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
#endif // C++20
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
|
@ -576,6 +602,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__cmpexch_failure_order(__m));
|
||||
}
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(__int_type __old,
|
||||
memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{
|
||||
std::__atomic_wait(&_M_i, __old,
|
||||
[__m, this, __old]
|
||||
{ return this->load(__m) != __old; });
|
||||
}
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ std::__atomic_notify(&_M_i, false); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ std::__atomic_notify(&_M_i, true); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
#endif // C++2a
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE __int_type
|
||||
fetch_add(__int_type __i,
|
||||
memory_order __m = memory_order_seq_cst) noexcept
|
||||
|
@ -845,6 +896,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
int(__m1), int(__m2));
|
||||
}
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(__pointer_type __old,
|
||||
memory_order __m = memory_order_seq_cst) noexcept
|
||||
{
|
||||
std::__atomic_wait(&_M_p, __old,
|
||||
[__m, this, __old]()
|
||||
{ return this->load(__m) != __old; });
|
||||
}
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ std::__atomic_notify(&_M_p, false); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ std::__atomic_notify(&_M_p, true); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
#endif // C++2a
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE __pointer_type
|
||||
fetch_add(ptrdiff_t __d,
|
||||
memory_order __m = memory_order_seq_cst) noexcept
|
||||
|
@ -933,6 +1009,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
int(__success), int(__failure));
|
||||
}
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
template<typename _Tp>
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(const _Tp* __ptr, _Val<_Tp> __old,
|
||||
memory_order __m = memory_order_seq_cst) noexcept
|
||||
{
|
||||
std::__atomic_wait(__ptr, __old,
|
||||
[=]() { return load(__ptr, __m) == __old; });
|
||||
}
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
template<typename _Tp>
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one(const _Tp* __ptr) noexcept
|
||||
{ std::__atomic_notify(__ptr, false); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
template<typename _Tp>
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all(const _Tp* __ptr) noexcept
|
||||
{ std::__atomic_notify(__ptr, true); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
#endif // C++2a
|
||||
|
||||
template<typename _Tp>
|
||||
_GLIBCXX_ALWAYS_INLINE _Tp
|
||||
fetch_add(_Tp* __ptr, _Diff<_Tp> __i, memory_order __m) noexcept
|
||||
|
@ -1186,6 +1289,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__cmpexch_failure_order(__order));
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{ __atomic_impl::wait(&_M_fp, __old, __m); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ __atomic_impl::notify_one(&_M_fp); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ __atomic_impl::notify_all(&_M_fp); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
value_type
|
||||
fetch_add(value_type __i,
|
||||
memory_order __m = memory_order_seq_cst) noexcept
|
||||
|
@ -1323,6 +1444,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__cmpexch_failure_order(__order));
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{ __atomic_impl::wait(_M_ptr, __old, __m); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ __atomic_impl::notify_one(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ __atomic_impl::notify_all(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
private:
|
||||
_Tp* _M_ptr;
|
||||
};
|
||||
|
@ -1418,6 +1557,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__cmpexch_failure_order(__order));
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{ __atomic_impl::wait(_M_ptr, __old, __m); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ __atomic_impl::notify_one(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ __atomic_impl::notify_all(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
value_type
|
||||
fetch_add(value_type __i,
|
||||
memory_order __m = memory_order_seq_cst) const noexcept
|
||||
|
@ -1573,6 +1730,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__cmpexch_failure_order(__order));
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(_Fp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{ __atomic_impl::wait(_M_ptr, __old, __m); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ __atomic_impl::notify_one(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ __atomic_impl::notify_all(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
value_type
|
||||
fetch_add(value_type __i,
|
||||
memory_order __m = memory_order_seq_cst) const noexcept
|
||||
|
@ -1682,6 +1857,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__cmpexch_failure_order(__order));
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
|
||||
{ __atomic_impl::wait(_M_ptr, __old, __m); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_one() const noexcept
|
||||
{ __atomic_impl::notify_one(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
notify_all() const noexcept
|
||||
{ __atomic_impl::notify_all(_M_ptr); }
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE value_type
|
||||
fetch_add(difference_type __d,
|
||||
memory_order __m = memory_order_seq_cst) const noexcept
|
||||
|
|
287
libstdc++-v3/include/bits/atomic_timed_wait.h
Normal file
287
libstdc++-v3/include/bits/atomic_timed_wait.h
Normal file
|
@ -0,0 +1,287 @@
|
|||
// -*- C++ -*- header.
|
||||
|
||||
// Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// Under Section 7 of GPL version 3, you are granted additional
|
||||
// permissions described in the GCC Runtime Library Exception, version
|
||||
// 3.1, as published by the Free Software Foundation.
|
||||
|
||||
// You should have received a copy of the GNU General Public License and
|
||||
// a copy of the GCC Runtime Library Exception along with this program;
|
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file bits/atomic_timed_wait.h
|
||||
* This is an internal header file, included by other library headers.
|
||||
* Do not attempt to use it directly. @headername{atomic}
|
||||
*/
|
||||
|
||||
#ifndef _GLIBCXX_ATOMIC_TIMED_WAIT_H
|
||||
#define _GLIBCXX_ATOMIC_TIMED_WAIT_H 1
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <bits/c++config.h>
|
||||
#include <bits/functional_hash.h>
|
||||
#include <bits/atomic_wait.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
enum class __atomic_wait_status { no_timeout, timeout };
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
|
||||
using __platform_wait_clock_t = chrono::steady_clock;
|
||||
|
||||
template<typename _Duration>
|
||||
__atomic_wait_status
|
||||
__platform_wait_until_impl(__platform_wait_t* __addr,
|
||||
__platform_wait_t __val,
|
||||
const chrono::time_point<
|
||||
__platform_wait_clock_t, _Duration>&
|
||||
__atime) noexcept
|
||||
{
|
||||
auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
|
||||
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
|
||||
|
||||
struct timespec __rt =
|
||||
{
|
||||
static_cast<std::time_t>(__s.time_since_epoch().count()),
|
||||
static_cast<long>(__ns.count())
|
||||
};
|
||||
|
||||
auto __e = syscall (SYS_futex, __addr,
|
||||
static_cast<int>(__futex_wait_flags::
|
||||
__wait_bitset_private),
|
||||
__val, &__rt, nullptr,
|
||||
static_cast<int>(__futex_wait_flags::
|
||||
__bitset_match_any));
|
||||
if (__e && !(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT))
|
||||
std::terminate();
|
||||
return (__platform_wait_clock_t::now() < __atime)
|
||||
? __atomic_wait_status::no_timeout
|
||||
: __atomic_wait_status::timeout;
|
||||
}
|
||||
|
||||
template<typename _Clock, typename _Duration>
|
||||
__atomic_wait_status
|
||||
__platform_wait_until(__platform_wait_t* __addr, __platform_wait_t __val,
|
||||
const chrono::time_point<_Clock, _Duration>&
|
||||
__atime)
|
||||
{
|
||||
if constexpr (is_same_v<__platform_wait_clock_t, _Clock>)
|
||||
{
|
||||
return __detail::__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 (__detail::__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 (std::__detail::__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 __detail::__platform_wait_until(&_M_ver, __version, __atime);
|
||||
#else
|
||||
__platform_wait_t __cur = 0;
|
||||
__waiters::__lock_t __l(_M_mtx);
|
||||
while (__cur <= __version)
|
||||
{
|
||||
if (__detail::__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 static_cast<__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 = __detail::__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
|
306
libstdc++-v3/include/bits/atomic_wait.h
Normal file
306
libstdc++-v3/include/bits/atomic_wait.h
Normal file
|
@ -0,0 +1,306 @@
|
|||
// -*- 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
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
constexpr auto __atomic_spin_count_1 = 16;
|
||||
constexpr auto __atomic_spin_count_2 = 12;
|
||||
|
||||
inline constexpr
|
||||
auto __platform_wait_max_value =
|
||||
__gnu_cxx::__int_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 class __futex_wait_flags : int
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
|
||||
__private_flag = 128,
|
||||
#else
|
||||
__private_flag = 0,
|
||||
#endif
|
||||
__wait = 0,
|
||||
__wake = 1,
|
||||
__wait_bitset = 9,
|
||||
__wake_bitset = 10,
|
||||
__wait_private = __wait | __private_flag,
|
||||
__wake_private = __wake | __private_flag,
|
||||
__wait_bitset_private = __wait_bitset | __private_flag,
|
||||
__wake_bitset_private = __wake_bitset | __private_flag,
|
||||
__bitset_match_any = -1
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
void
|
||||
__platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
|
||||
static_cast<int>(__futex_wait_flags::__wait_private),
|
||||
__val, nullptr);
|
||||
if (!__e)
|
||||
break;
|
||||
else if (!(errno == EINTR || errno == EAGAIN))
|
||||
__throw_system_error(__e);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Tp>
|
||||
void
|
||||
__platform_notify(const _Tp* __addr, bool __all) noexcept
|
||||
{
|
||||
syscall (SYS_futex, static_cast<const void*>(__addr),
|
||||
static_cast<int>(__futex_wait_flags::__wake_private),
|
||||
__all ? INT_MAX : 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct __waiters
|
||||
{
|
||||
alignas(64) __platform_wait_t _M_ver = 0;
|
||||
alignas(64) __platform_wait_t _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)
|
||||
__throw_system_error(__e);
|
||||
__platform_wait_t __last = __cur;
|
||||
__atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
|
||||
if (__cur < __last)
|
||||
break; // break the loop if version overflows
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
_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(const 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(static_cast<const 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 < __detail::__atomic_spin_count_1; ++__i)
|
||||
{
|
||||
if (__pred())
|
||||
return true;
|
||||
|
||||
if (__i < __detail::__atomic_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 (std::__atomic_spin(__pred))
|
||||
return;
|
||||
|
||||
__waiter __w(__addr);
|
||||
while (!__pred())
|
||||
{
|
||||
if constexpr (__platform_wait_uses_type<_Tp>)
|
||||
{
|
||||
__platform_wait(__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
|
296
libstdc++-v3/include/bits/semaphore_base.h
Normal file
296
libstdc++-v3/include/bits/semaphore_base.h
Normal file
|
@ -0,0 +1,296 @@
|
|||
// -*- 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>
|
||||
|
||||
#include <ext/numeric_traits.h>
|
||||
|
||||
#if __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
|
||||
struct __platform_semaphore
|
||||
{
|
||||
using __clock_t = chrono::system_clock;
|
||||
static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
|
||||
|
||||
explicit __platform_semaphore(ptrdiff_t __count) noexcept
|
||||
{
|
||||
sem_init(&_M_semaphore, 0, __count);
|
||||
}
|
||||
|
||||
__platform_semaphore(const __platform_semaphore&) = delete;
|
||||
__platform_semaphore& operator=(const __platform_semaphore&) = delete;
|
||||
|
||||
~__platform_semaphore()
|
||||
{ sem_destroy(&_M_semaphore); }
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_M_acquire() noexcept
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto __err = sem_wait(&_M_semaphore);
|
||||
if (__err && (errno == EINTR))
|
||||
continue;
|
||||
else if (__err)
|
||||
std::terminate();
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_M_release(std::ptrdiff_t __update) noexcept
|
||||
{
|
||||
for(; __update != 0; --__update)
|
||||
{
|
||||
auto __err = sem_post(&_M_semaphore);
|
||||
if (__err)
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
_M_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())
|
||||
};
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (auto __err = sem_timedwait(&_M_semaphore, &__ts))
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else if (errno == ETIMEDOUT || errno == EINVAL)
|
||||
return false;
|
||||
else
|
||||
std::terminate();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _Clock, typename _Duration>
|
||||
bool
|
||||
_M_try_acquire_until(const chrono::time_point<_Clock,
|
||||
_Duration>& __atime) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<__clock_t, _Clock>)
|
||||
{
|
||||
return _M_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 (_M_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
|
||||
_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
|
||||
noexcept
|
||||
{ return _M_try_acquire_until(__clock_t::now() + __rtime); }
|
||||
|
||||
private:
|
||||
sem_t _M_semaphore;
|
||||
};
|
||||
#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
|
||||
template<typename _Tp>
|
||||
struct __atomic_semaphore
|
||||
{
|
||||
static_assert(std::is_integral_v<_Tp>);
|
||||
static_assert(__gnu_cxx::__int_traits<_Tp>::__max
|
||||
<= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
|
||||
static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
|
||||
|
||||
explicit __atomic_semaphore(_Tp __count) noexcept
|
||||
: _M_counter(__count)
|
||||
{
|
||||
__glibcxx_assert(__count >= 0 && __count <= _S_max);
|
||||
}
|
||||
|
||||
__atomic_semaphore(const __atomic_semaphore&) = delete;
|
||||
__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_M_acquire() noexcept
|
||||
{
|
||||
auto const __pred = [this]
|
||||
{
|
||||
auto __old = __atomic_impl::load(&this->_M_counter,
|
||||
memory_order::acquire);
|
||||
if (__old == 0)
|
||||
return false;
|
||||
return __atomic_impl::compare_exchange_strong(&this->_M_counter,
|
||||
__old, __old - 1,
|
||||
memory_order::acquire,
|
||||
memory_order::release);
|
||||
};
|
||||
auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
|
||||
std::__atomic_wait(&_M_counter, __old, __pred);
|
||||
}
|
||||
|
||||
bool
|
||||
_M_try_acquire() noexcept
|
||||
{
|
||||
auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
|
||||
auto const __pred = [this, __old]
|
||||
{
|
||||
if (__old == 0)
|
||||
return false;
|
||||
|
||||
auto __prev = __old;
|
||||
return __atomic_impl::compare_exchange_weak(&this->_M_counter,
|
||||
__prev, __prev - 1,
|
||||
memory_order::acquire,
|
||||
memory_order::release);
|
||||
};
|
||||
return std::__atomic_spin(__pred);
|
||||
}
|
||||
|
||||
template<typename _Clock, typename _Duration>
|
||||
_GLIBCXX_ALWAYS_INLINE bool
|
||||
_M_try_acquire_until(const chrono::time_point<_Clock,
|
||||
_Duration>& __atime) noexcept
|
||||
{
|
||||
auto const __pred = [this]
|
||||
{
|
||||
auto __old = __atomic_impl::load(&this->_M_counter,
|
||||
memory_order::acquire);
|
||||
if (__old == 0)
|
||||
return false;
|
||||
return __atomic_impl::compare_exchange_strong(&this->_M_counter,
|
||||
__old, __old - 1,
|
||||
memory_order::acquire,
|
||||
memory_order::release);
|
||||
};
|
||||
|
||||
auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
|
||||
return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
|
||||
}
|
||||
|
||||
template<typename _Rep, typename _Period>
|
||||
_GLIBCXX_ALWAYS_INLINE bool
|
||||
_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
|
||||
noexcept
|
||||
{
|
||||
auto const __pred = [this]
|
||||
{
|
||||
auto __old = __atomic_impl::load(&this->_M_counter,
|
||||
memory_order::acquire);
|
||||
if (__old == 0)
|
||||
return false;
|
||||
return __atomic_impl::compare_exchange_strong(&this->_M_counter,
|
||||
__old, __old - 1,
|
||||
memory_order::acquire,
|
||||
memory_order::release);
|
||||
};
|
||||
|
||||
auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
|
||||
return __atomic_wait_for(&_M_counter, __old, __pred, __rtime);
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_M_release(ptrdiff_t __update) noexcept
|
||||
{
|
||||
if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
|
||||
return;
|
||||
if (__update > 1)
|
||||
__atomic_impl::notify_all(&_M_counter);
|
||||
else
|
||||
__atomic_impl::notify_one(&_M_counter);
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(__alignof__(_Tp)) _Tp _M_counter;
|
||||
};
|
||||
|
||||
// Note: the _GLIBCXX_REQUIRE_POSIX_SEMAPHORE macro can be used to force the
|
||||
// use of Posix semaphores (sem_t). Doing so however, alters the ABI.
|
||||
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
|
||||
// Use futex if available and didn't force use of POSIX
|
||||
using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
|
||||
#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
using __fast_semaphore = __platform_semaphore;
|
||||
#else
|
||||
using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
|
||||
#endif
|
||||
|
||||
template<ptrdiff_t __least_max_value>
|
||||
using __semaphore_impl = conditional_t<
|
||||
(__least_max_value > 1),
|
||||
conditional_t<
|
||||
(__least_max_value <= __fast_semaphore::_S_max),
|
||||
__fast_semaphore,
|
||||
__atomic_semaphore<ptrdiff_t>>,
|
||||
__fast_semaphore>;
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
|
||||
#endif
|
|
@ -163,6 +163,20 @@ _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
|
||||
|
@ -363,6 +377,30 @@ _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) const noexcept
|
||||
{
|
||||
std::__atomic_wait(&_M_i, __old,
|
||||
[__m, this, __old]
|
||||
{
|
||||
const auto __v = this->load(__m);
|
||||
// TODO make this ignore padding bits when we
|
||||
// can do that
|
||||
return __builtin_memcmp(&__old, &__v,
|
||||
sizeof(_Tp)) != 0;
|
||||
});
|
||||
}
|
||||
|
||||
// TODO add const volatile overload
|
||||
|
||||
void notify_one() const noexcept
|
||||
{ std::__atomic_notify(&_M_i, false); }
|
||||
|
||||
void notify_all() const noexcept
|
||||
{ std::__atomic_notify(&_M_i, true); }
|
||||
#endif
|
||||
|
||||
};
|
||||
#undef _GLIBCXX20_INIT
|
||||
|
||||
|
@ -601,6 +639,19 @@ _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
|
||||
|
@ -1353,6 +1404,33 @@ _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>*.
|
||||
|
|
91
libstdc++-v3/include/std/latch
Normal file
91
libstdc++-v3/include/std/latch
Normal file
|
@ -0,0 +1,91 @@
|
|||
// <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 ptrdiff_t
|
||||
max() noexcept
|
||||
{ return __gnu_cxx::__int_traits<ptrdiff_t>::__max; }
|
||||
|
||||
constexpr explicit latch(ptrdiff_t __expected) noexcept
|
||||
: _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 noexcept
|
||||
{
|
||||
auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
|
||||
std::__atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
arrive_and_wait(ptrdiff_t __update = 1) noexcept
|
||||
{
|
||||
count_down(__update);
|
||||
wait();
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
|
||||
};
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
#endif // __cplusplus > 201703L
|
||||
#endif // _GLIBCXX_LATCH
|
92
libstdc++-v3/include/std/semaphore
Normal file
92
libstdc++-v3/include/std/semaphore
Normal file
|
@ -0,0 +1,92 @@
|
|||
// <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::__int_traits<ptrdiff_t>::__max>
|
||||
class counting_semaphore
|
||||
{
|
||||
static_assert(__least_max_value >= 0);
|
||||
|
||||
__semaphore_impl<__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) noexcept(noexcept(_M_sem._M_release(1)))
|
||||
{ _M_sem._M_release(__update); }
|
||||
|
||||
void
|
||||
acquire() noexcept(noexcept(_M_sem._M_acquire()))
|
||||
{ _M_sem._M_acquire(); }
|
||||
|
||||
bool
|
||||
try_acquire() noexcept(noexcept(_M_sem._M_try_acquire()))
|
||||
{ return _M_sem._M_try_acquire(); }
|
||||
|
||||
template<typename _Rep, typename _Period>
|
||||
bool
|
||||
try_acquire_for(const std::chrono::duration<_Rep, _Period>& __rtime)
|
||||
{ return _M_sem._M_try_acquire_for(__rtime); }
|
||||
|
||||
template<typename _Clock, typename _Dur>
|
||||
bool
|
||||
try_acquire_until(const std::chrono::time_point<_Clock, _Dur>& __atime)
|
||||
{ return _M_sem._M_try_acquire_until(__atime); }
|
||||
};
|
||||
|
||||
using binary_semaphore = std::counting_semaphore<1>;
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
#endif // __cplusplus > 201703L
|
||||
#endif // _GLIBCXX_SEMAPHORE
|
|
@ -216,6 +216,7 @@
|
|||
#ifdef _GLIBCXX_HAS_GTHREADS
|
||||
# define __cpp_lib_jthread 201911L
|
||||
#endif
|
||||
#define __cpp_lib_latch 201907L
|
||||
#define __cpp_lib_list_remove_return_type 201806L
|
||||
#if __cpp_lib_concepts
|
||||
# define __cpp_lib_make_obj_using_allocator 201811L
|
||||
|
@ -225,6 +226,7 @@
|
|||
#if __cpp_lib_concepts
|
||||
# define __cpp_lib_ranges 201911L
|
||||
#endif
|
||||
#define __cpp_lib_semaphore 201907L
|
||||
#define __cpp_lib_shift 201806L
|
||||
#if __cpp_lib_concepts
|
||||
# define __cpp_lib_span 202002L
|
||||
|
|
59
libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
Normal file
59
libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/bool.cc
Normal file
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// { 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/wait_notify_util.h"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
struct S{ int i; };
|
||||
check<S> check_s{S{0},S{42}};
|
||||
return 0;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// { 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 <chrono>
|
||||
#include <condition_variable>
|
||||
#include <concepts>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
|
||||
std::atomic_flag a;
|
||||
std::atomic_flag b;
|
||||
std::thread t([&]
|
||||
{
|
||||
cv.notify_one();
|
||||
a.wait(false);
|
||||
b.test_and_set();
|
||||
b.notify_one();
|
||||
});
|
||||
|
||||
std::unique_lock<std::mutex> l(m);
|
||||
cv.wait(l);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
a.test_and_set();
|
||||
a.notify_one();
|
||||
b.wait(false);
|
||||
t.join();
|
||||
|
||||
VERIFY( a.test() );
|
||||
VERIFY( b.test() );
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// { 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/wait_notify_util.h"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
check<float> f;
|
||||
check<double> d;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
// { 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/wait_notify_util.h"
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
struct S{ int i; };
|
||||
std::atomic<S> s;
|
||||
|
||||
s.wait(S{42});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
90
libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
Normal file
90
libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
Normal file
|
@ -0,0 +1,90 @@
|
|||
// { 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 <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);
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
check<long>();
|
||||
check<double>();
|
||||
return 0;
|
||||
}
|
27
libstdc++-v3/testsuite/30_threads/latch/1.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/latch/1.cc
Normal file
|
@ -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
|
27
libstdc++-v3/testsuite/30_threads/latch/2.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/latch/2.cc
Normal file
|
@ -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 <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
|
69
libstdc++-v3/testsuite/30_threads/latch/3.cc
Normal file
69
libstdc++-v3/testsuite/30_threads/latch/3.cc
Normal file
|
@ -0,0 +1,69 @@
|
|||
// 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 -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>
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
std::latch l(3);
|
||||
|
||||
VERIFY( !l.try_wait() );
|
||||
|
||||
auto fn = [&]
|
||||
{
|
||||
l.count_down();
|
||||
};
|
||||
|
||||
std::thread t0(fn);
|
||||
std::thread t1(fn);
|
||||
|
||||
l.arrive_and_wait();
|
||||
t0.join();
|
||||
t1.join();
|
||||
|
||||
VERIFY( l.try_wait() );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
std::latch l(3);
|
||||
std::thread t([&]
|
||||
{
|
||||
l.count_down();
|
||||
});
|
||||
|
||||
l.arrive_and_wait(2);
|
||||
t.join();
|
||||
VERIFY( l.try_wait() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
return 0;
|
||||
}
|
27
libstdc++-v3/testsuite/30_threads/semaphore/1.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/semaphore/1.cc
Normal file
|
@ -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
|
27
libstdc++-v3/testsuite/30_threads/semaphore/2.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/semaphore/2.cc
Normal file
|
@ -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 <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
|
|
@ -0,0 +1,30 @@
|
|||
// 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 } }
|
||||
// { dg-require-effective-target pthread }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
#include <semaphore>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::counting_semaphore<-1> sem(2);
|
||||
return 0;
|
||||
}
|
||||
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
|
55
libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
Normal file
55
libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
Normal file
|
@ -0,0 +1,55 @@
|
|||
// 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 -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();
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// 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 -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();
|
||||
}
|
153
libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
Normal file
153
libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
Normal file
|
@ -0,0 +1,153 @@
|
|||
// 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 -pthread" }
|
||||
// { dg-do run { target c++2a } }
|
||||
// { dg-require-effective-target pthread }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
#include <semaphore>
|
||||
#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void test01()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(2);
|
||||
s._M_acquire();
|
||||
|
||||
auto const dur = 250ms;
|
||||
{
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
VERIFY( s._M_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._M_try_acquire_for(dur) );
|
||||
auto const diff = std::chrono::steady_clock::now() - t0;
|
||||
VERIFY( diff >= dur );
|
||||
}
|
||||
}
|
||||
|
||||
void test02()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(1);
|
||||
std::atomic<int> a(0), b(0);
|
||||
std::thread t([&] {
|
||||
a.wait(0);
|
||||
auto const dur = 250ms;
|
||||
VERIFY( !s._M_try_acquire_for(dur) );
|
||||
b++;
|
||||
b.notify_one();
|
||||
|
||||
a.wait(1);
|
||||
VERIFY( s._M_try_acquire_for(dur) );
|
||||
b++;
|
||||
b.notify_one();
|
||||
});
|
||||
t.detach();
|
||||
|
||||
s._M_acquire();
|
||||
a++;
|
||||
a.notify_one();
|
||||
b.wait(0);
|
||||
s._M_release(1);
|
||||
a++;
|
||||
a.notify_one();
|
||||
|
||||
b.wait(1);
|
||||
}
|
||||
|
||||
void test03()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(2);
|
||||
s._M_acquire();
|
||||
|
||||
auto const dur = 250ms;
|
||||
{
|
||||
auto const at = std::chrono::system_clock::now() + dur;
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
VERIFY( s._M_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._M_try_acquire_until(at) );
|
||||
auto const diff = std::chrono::steady_clock::now() - t0;
|
||||
VERIFY( diff >= dur );
|
||||
}
|
||||
}
|
||||
|
||||
void test04()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_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._M_try_acquire_until(at) );
|
||||
|
||||
b++;
|
||||
b.notify_one();
|
||||
}
|
||||
|
||||
a.wait(1);
|
||||
{
|
||||
auto const at = std::chrono::system_clock::now() + dur;
|
||||
VERIFY( s._M_try_acquire_until(at) );
|
||||
}
|
||||
b++;
|
||||
b.notify_one();
|
||||
});
|
||||
t.detach();
|
||||
|
||||
s._M_acquire();
|
||||
a++;
|
||||
a.notify_one();
|
||||
b.wait(0);
|
||||
s._M_release(1);
|
||||
a++;
|
||||
a.notify_one();
|
||||
|
||||
b.wait(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
test04();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// 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 -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();
|
||||
}
|
160
libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
Normal file
160
libstdc++-v3/testsuite/util/atomic/wait_notify_util.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
// 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 <chrono>
|
||||
#include <condition_variable>
|
||||
#include <concepts>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template<typename Tp>
|
||||
Tp check_wait_notify(Tp val1, Tp val2)
|
||||
requires std::equality_comparable<Tp>
|
||||
{
|
||||
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_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);
|
||||
auto v = a.load();
|
||||
// TODO this needs to zero padding bits when we can do that
|
||||
if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
|
||||
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)
|
||||
requires std::equality_comparable<Tp>
|
||||
{
|
||||
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>
|
||||
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);
|
||||
auto v = a.load();
|
||||
// TODO this needs to zero padding bits when we can do that
|
||||
if (__builtin_memcmp(&v, &val2, sizeof(Tp)) != 0)
|
||||
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)
|
||||
{
|
||||
if constexpr (std::equality_comparable<Tp>)
|
||||
{
|
||||
VERIFY( check_wait_notify(a, b) == b);
|
||||
VERIFY( check_atomic_wait_notify(a, b) == b);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
// TODO this needs to zero padding bits when we can do that
|
||||
auto v = check_wait_notify(a, b);
|
||||
VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0 );
|
||||
}
|
||||
|
||||
{
|
||||
// TODO this needs to zero padding bits when we can do that
|
||||
auto v = check_atomic_wait_notify(a, b);
|
||||
VERIFY( __builtin_memcmp(&v, &b, sizeof(Tp)) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue