[libc++] Implementation of C++20's P1135R6 for libcxx

Differential Revision: https://reviews.llvm.org/D68480
This commit is contained in:
Olivier Giroux
2020-02-18 09:58:34 -05:00
committed by Louis Dionne
parent d66d25f838
commit 54fa9ecd30
33 changed files with 2133 additions and 7 deletions

View File

@@ -25,6 +25,7 @@ set(files
any
array
atomic
barrier
bit
bitset
cassert
@@ -103,6 +104,7 @@ set(files
iostream
istream
iterator
latch
limits
limits.h
list
@@ -122,6 +124,7 @@ set(files
ratio
regex
scoped_allocator
semaphore
set
setjmp.h
shared_mutex

View File

@@ -26,6 +26,10 @@
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
# include <pthread.h>
# include <sched.h>
# include <semaphore.h>
# ifdef __APPLE__
# define _LIBCPP_NO_NATIVE_SEMAPHORES
# endif
#elif defined(_LIBCPP_HAS_THREAD_API_C11)
# include <threads.h>
#endif
@@ -65,6 +69,10 @@ typedef pthread_mutex_t __libcpp_recursive_mutex_t;
typedef pthread_cond_t __libcpp_condvar_t;
#define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
// Semaphore
typedef sem_t __libcpp_semaphore_t;
#define _LIBCPP_SEMAPHORE_MAX SEM_VALUE_MAX
// Execute once
typedef pthread_once_t __libcpp_exec_once_flag;
#define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
@@ -127,6 +135,9 @@ typedef void* __libcpp_recursive_mutex_t[5];
typedef void* __libcpp_condvar_t;
#define _LIBCPP_CONDVAR_INITIALIZER 0
// Semaphore
typedef void* __libcpp_semaphore_t;
// Execute Once
typedef void* __libcpp_exec_once_flag;
#define _LIBCPP_EXEC_ONCE_INITIALIZER 0
@@ -191,6 +202,22 @@ int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
_LIBCPP_THREAD_ABI_VISIBILITY
int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
// Semaphore
_LIBCPP_THREAD_ABI_VISIBILITY
bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init);
_LIBCPP_THREAD_ABI_VISIBILITY
bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem);
_LIBCPP_THREAD_ABI_VISIBILITY
bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem);
_LIBCPP_THREAD_ABI_VISIBILITY
bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem);
_LIBCPP_THREAD_ABI_VISIBILITY
bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns);
// Execute once
_LIBCPP_THREAD_ABI_VISIBILITY
int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
@@ -229,6 +256,16 @@ void __libcpp_thread_yield();
_LIBCPP_THREAD_ABI_VISIBILITY
void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns);
struct __libcpp_timed_backoff_policy {
_LIBCPP_THREAD_ABI_VISIBILITY
bool operator()(chrono::nanoseconds __elapsed) const;
};
template<class _Fn, class _BFn>
_LIBCPP_INLINE_VISIBILITY
bool __libcpp_thread_poll_with_backoff(
_Fn && __f, _BFn && __bf, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero());
// Thread local storage
_LIBCPP_THREAD_ABI_VISIBILITY
int __libcpp_tls_create(__libcpp_tls_key* __key,
@@ -364,6 +401,38 @@ int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
return pthread_cond_destroy(__cv);
}
#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
// Semaphore
bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init)
{
return sem_init(__sem, 0, __init) == 0;
}
bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem)
{
return sem_destroy(__sem) == 0;
}
bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem)
{
return sem_post(__sem) == 0;
}
bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem)
{
return sem_wait(__sem) == 0;
}
bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns)
{
auto const __abs_time = chrono::system_clock::now().time_since_epoch() + __ns;
__libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__abs_time);
return sem_timedwait(__sem, &__ts) == 0;
}
#endif //_LIBCPP_NO_NATIVE_SEMAPHORES
// Execute once
int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
void (*init_routine)()) {
@@ -425,6 +494,40 @@ void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR);
}
bool __libcpp_timed_backoff_policy::operator()(chrono::nanoseconds __elapsed) const
{
if(__elapsed > chrono::milliseconds(128))
__libcpp_thread_sleep_for(chrono::milliseconds(8));
else if(__elapsed > chrono::microseconds(64))
__libcpp_thread_sleep_for(__elapsed / 2);
else if(__elapsed > chrono::microseconds(4))
__libcpp_thread_yield();
else
; // poll
return false;
}
static constexpr int __libcpp_polling_count = 64;
template<class _Fn, class _BFn>
bool __libcpp_thread_poll_with_backoff(_Fn && __f, _BFn && __bf, chrono::nanoseconds __max_elapsed)
{
auto const __start = chrono::high_resolution_clock::now();
for(int __count = 0;;) {
if(__f())
return true; // _Fn completion means success
if(__count < __libcpp_polling_count) {
__count += 1;
continue;
}
chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start;
if(__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed)
return false; // timeout failure
if(__bf(__elapsed))
return false; // _BFn completion means failure
}
}
// Thread local storage
int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
{

View File

@@ -547,8 +547,10 @@ void atomic_signal_fence(memory_order m) noexcept;
*/
#include <__config>
#include <__threading_support>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <version>
@@ -629,6 +631,11 @@ typedef enum memory_order {
#endif // _LIBCPP_STD_VER > 17
template <typename _Tp> _LIBCPP_INLINE_VISIBILITY
bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp const& __rhs) {
return memcmp(&__lhs, &__rhs, sizeof(_Tp)) == 0;
}
static_assert((is_same<underlying_type<memory_order>::type, __memory_order_underlying_t>::value),
"unexpected underlying type for std::memory_order");
@@ -1218,9 +1225,9 @@ _LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp* __expected, _Tp __value, memory_order, memory_order) {
__a->__lock();
_Tp temp;
__cxx_atomic_assign_volatile(temp, __a->__a_value);
bool __ret = temp == *__expected;
_Tp __temp;
__cxx_atomic_assign_volatile(__temp, __a->__a_value);
bool __ret = __temp == *__expected;
if(__ret)
__cxx_atomic_assign_volatile(__a->__a_value, __value);
else
@@ -1247,9 +1254,9 @@ _LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp* __expected, _Tp __value, memory_order, memory_order) {
__a->__lock();
_Tp temp;
__cxx_atomic_assign_volatile(temp, __a->__a_value);
bool __ret = temp == *__expected;
_Tp __temp;
__cxx_atomic_assign_volatile(__temp, __a->__a_value);
bool __ret = __temp == *__expected;
if(__ret)
__cxx_atomic_assign_volatile(__a->__a_value, __value);
else
@@ -1452,6 +1459,73 @@ struct __cxx_atomic_impl : public _Base {
: _Base(value) {}
};
#ifdef __linux__
using __cxx_contention_t = int32_t;
#else
using __cxx_contention_t = int64_t;
#endif //__linux__
#if _LIBCPP_STD_VER >= 11
using __cxx_atomic_contention_t = __cxx_atomic_impl<__cxx_contention_t>;
#ifndef _LIBCPP_HAS_NO_PLATFORM_WAIT
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*);
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*);
_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile*);
_LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(void const volatile*, __cxx_contention_t);
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*);
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*);
_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*);
_LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t);
template <class _Atp, class _Fn>
_LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp* __a, _Fn && __test_fn)
{
auto const __libcpp_atomic_wait_backoff = [=](chrono::nanoseconds __elapsed) -> bool {
if(__elapsed > chrono::microseconds(64))
{
auto const __monitor = __libcpp_atomic_monitor(__a);
if(__test_fn())
return true;
__libcpp_atomic_wait(__a, __monitor);
}
else if(__elapsed > chrono::microseconds(4))
__libcpp_thread_yield();
else
; // poll
return false;
};
return __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_atomic_wait_backoff);
}
#else // _LIBCPP_HAS_NO_PLATFORM_WAIT
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY void __cxx_atomic_notify_all(__cxx_atomic_impl<_Tp> const volatile*) { }
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY void __cxx_atomic_notify_one(__cxx_atomic_impl<_Tp> const volatile*) { }
template <class _Atp, class _Fn>
_LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp*, _Fn && __test_fn)
{
return __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
}
#endif // _LIBCPP_HAS_NO_PLATFORM_WAIT
template <class _Atp, class _Tp>
_LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp* __a, _Tp const __val, memory_order __order)
{
auto const __test_fn = [=]() -> bool {
return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__a, __order), __val);
};
return __cxx_atomic_wait(__a, __test_fn);
}
#endif //_LIBCPP_STD_VER >= 11
// general atomic<T>
template <class _Tp, bool = is_integral<_Tp>::value && !is_same<_Tp, bool>::value>
@@ -1532,6 +1606,19 @@ struct __atomic_base // false
memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);}
_LIBCPP_INLINE_VISIBILITY void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
{__cxx_atomic_wait(&__a_, __v, __m);}
_LIBCPP_INLINE_VISIBILITY void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT
{__cxx_atomic_wait(&__a_, __v, __m);}
_LIBCPP_INLINE_VISIBILITY void notify_one() volatile _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_INLINE_VISIBILITY void notify_one() _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_INLINE_VISIBILITY void notify_all() volatile _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
_LIBCPP_INLINE_VISIBILITY void notify_all() _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
_LIBCPP_INLINE_VISIBILITY
__atomic_base() _NOEXCEPT _LIBCPP_DEFAULT
@@ -1544,8 +1631,11 @@ struct __atomic_base // false
__atomic_base& operator=(const __atomic_base&) volatile = delete;
#else
private:
_LIBCPP_INLINE_VISIBILITY
__atomic_base(const __atomic_base&);
_LIBCPP_INLINE_VISIBILITY
__atomic_base& operator=(const __atomic_base&);
_LIBCPP_INLINE_VISIBILITY
__atomic_base& operator=(const __atomic_base&) volatile;
#endif
};
@@ -1643,6 +1733,7 @@ struct atomic
: public __atomic_base<_Tp>
{
typedef __atomic_base<_Tp> __base;
typedef _Tp value_type;
_LIBCPP_INLINE_VISIBILITY
atomic() _NOEXCEPT _LIBCPP_DEFAULT
_LIBCPP_INLINE_VISIBILITY
@@ -1663,6 +1754,7 @@ struct atomic<_Tp*>
: public __atomic_base<_Tp*>
{
typedef __atomic_base<_Tp*> __base;
typedef _Tp* value_type;
_LIBCPP_INLINE_VISIBILITY
atomic() _NOEXCEPT _LIBCPP_DEFAULT
_LIBCPP_INLINE_VISIBILITY
@@ -1947,6 +2039,76 @@ atomic_compare_exchange_strong_explicit(atomic<_Tp>* __o, _Tp* __e,
return __o->compare_exchange_strong(*__e, __d, __s, __f);
}
// atomic_wait
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_wait(const volatile atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v) _NOEXCEPT
{
return __o->wait(__v);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_wait(const atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v) _NOEXCEPT
{
return __o->wait(__v);
}
// atomic_wait_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_wait_explicit(const volatile atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v,
memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{
return __o->wait(__v, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_wait_explicit(const atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v,
memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{
return __o->wait(__v, __m);
}
// atomic_notify_one
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_notify_one(volatile atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_one();
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_notify_one(atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_one();
}
// atomic_notify_one
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_notify_all(volatile atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_all();
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void atomic_notify_all(atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_all();
}
// atomic_fetch_add
template <class _Tp>
@@ -2279,6 +2441,13 @@ typedef struct atomic_flag
{
__cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE> __a_;
_LIBCPP_INLINE_VISIBILITY
bool test(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
{return _LIBCPP_ATOMIC_FLAG_TYPE(true) == __cxx_atomic_load(&__a_, __m);}
_LIBCPP_INLINE_VISIBILITY
bool test(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
{return _LIBCPP_ATOMIC_FLAG_TYPE(true) == __cxx_atomic_load(&__a_, __m);}
_LIBCPP_INLINE_VISIBILITY
bool test_and_set(memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_exchange(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(true), __m);}
@@ -2292,6 +2461,25 @@ typedef struct atomic_flag
void clear(memory_order __m = memory_order_seq_cst) _NOEXCEPT
{__cxx_atomic_store(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(false), __m);}
_LIBCPP_INLINE_VISIBILITY
void wait(bool __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
{__cxx_atomic_wait(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);}
_LIBCPP_INLINE_VISIBILITY
void wait(bool __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT
{__cxx_atomic_wait(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);}
_LIBCPP_INLINE_VISIBILITY
void notify_one() volatile _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_INLINE_VISIBILITY
void notify_one() _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_INLINE_VISIBILITY
void notify_all() volatile _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
_LIBCPP_INLINE_VISIBILITY
void notify_all() _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
_LIBCPP_INLINE_VISIBILITY
atomic_flag() _NOEXCEPT _LIBCPP_DEFAULT
@@ -2304,12 +2492,44 @@ typedef struct atomic_flag
atomic_flag& operator=(const atomic_flag&) volatile = delete;
#else
private:
_LIBCPP_INLINE_VISIBILITY
atomic_flag(const atomic_flag&);
_LIBCPP_INLINE_VISIBILITY
atomic_flag& operator=(const atomic_flag&);
_LIBCPP_INLINE_VISIBILITY
atomic_flag& operator=(const atomic_flag&) volatile;
#endif
} atomic_flag;
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test(const volatile atomic_flag* __o) _NOEXCEPT
{
return __o->test();
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test(const atomic_flag* __o) _NOEXCEPT
{
return __o->test();
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_explicit(const volatile atomic_flag* __o, memory_order __m) _NOEXCEPT
{
return __o->test(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_explicit(const atomic_flag* __o, memory_order __m) _NOEXCEPT
{
return __o->test(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_and_set(volatile atomic_flag* __o) _NOEXCEPT
@@ -2366,6 +2586,64 @@ atomic_flag_clear_explicit(atomic_flag* __o, memory_order __m) _NOEXCEPT
__o->clear(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_wait(const volatile atomic_flag* __o, bool __v) _NOEXCEPT
{
__o->wait(__v);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_wait(const atomic_flag* __o, bool __v) _NOEXCEPT
{
__o->wait(__v);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_wait_explicit(const volatile atomic_flag* __o,
bool __v, memory_order __m) _NOEXCEPT
{
__o->wait(__v, __m);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_wait_explicit(const atomic_flag* __o,
bool __v, memory_order __m) _NOEXCEPT
{
__o->wait(__v, __m);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_notify_one(volatile atomic_flag* __o) _NOEXCEPT
{
__o->notify_one();
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_notify_one(atomic_flag* __o) _NOEXCEPT
{
__o->notify_one();
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_notify_all(volatile atomic_flag* __o) _NOEXCEPT
{
__o->notify_all();
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_notify_all(atomic_flag* __o) _NOEXCEPT
{
__o->notify_all();
}
// fences
inline _LIBCPP_INLINE_VISIBILITY
@@ -2434,6 +2712,33 @@ typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
typedef atomic<intmax_t> atomic_intmax_t;
typedef atomic<uintmax_t> atomic_uintmax_t;
// atomic_*_lock_free : prefer the contention type most highly, then the largest lock-free type
#ifdef __cpp_lib_atomic_is_always_lock_free
# define _LIBCPP_CONTENTION_LOCK_FREE __atomic_always_lock_free(sizeof(__cxx_contention_t), 0)
#else
# define _LIBCPP_CONTENTION_LOCK_FREE false
#endif
#if ATOMIC_LLONG_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, long long>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned long long>::type __libcpp_unsigned_lock_free;
#elif ATOMIC_INT_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, int>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned int>::type __libcpp_unsigned_lock_free;
#elif ATOMIC_SHORT_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, short>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned short>::type __libcpp_unsigned_lock_free;
#elif ATOMIC_CHAR_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, char>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned char>::type __libcpp_unsigned_lock_free;
#else
// No signed/unsigned lock-free types
#endif
typedef atomic<__libcpp_signed_lock_free> atomic_signed_lock_free;
typedef atomic<__libcpp_unsigned_lock_free> atomic_unsigned_lock_free;
#define ATOMIC_FLAG_INIT {false}
#define ATOMIC_VAR_INIT(__v) {__v}

322
libcxx/include/barrier Normal file
View File

@@ -0,0 +1,322 @@
// -*- C++ -*-
//===--------------------------- barrier ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_BARRIER
#define _LIBCPP_BARRIER
/*
barrier synopsis
namespace std
{
template<class CompletionFunction = see below>
class barrier
{
public:
using arrival_token = see below;
constexpr explicit barrier(ptrdiff_t phase_count,
CompletionFunction f = CompletionFunction());
~barrier();
barrier(const barrier&) = delete;
barrier& operator=(const barrier&) = delete;
[[nodiscard]] arrival_token arrive(ptrdiff_t update = 1);
void wait(arrival_token&& arrival) const;
void arrive_and_wait();
void arrive_and_drop();
private:
CompletionFunction completion; // exposition only
};
}
*/
#include <__config>
#include <atomic>
#ifndef _LIBCPP_HAS_NO_TREE_BARRIER
# include <memory>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
#ifdef _LIBCPP_HAS_NO_THREADS
# error <barrier> is not supported on this single threaded system
#endif
#if _LIBCPP_STD_VER < 14
# error <barrier> requires C++14 or later
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
struct __empty_completion
{
inline _LIBCPP_INLINE_VISIBILITY
void operator()() noexcept
{
}
};
#ifndef _LIBCPP_HAS_NO_TREE_BARRIER
/*
The default implementation of __barrier_base is a classic tree barrier.
It looks different from literature pseudocode for two main reasons:
1. Threads that call into std::barrier functions do not provide indices,
so a numbering step is added before the actual barrier algorithm,
appearing as an N+1 round to the N rounds of the tree barrier.
2. A great deal of attention has been paid to avoid cache line thrashing
by flattening the tree structure into cache-line sized arrays, that
are indexed in an efficient way.
*/
using __barrier_phase_t = uint8_t;
class __barrier_algorithm_base;
_LIBCPP_EXPORTED_FROM_ABI
__barrier_algorithm_base* __construct_barrier_algorithm_base(ptrdiff_t& __expected);
_LIBCPP_EXPORTED_FROM_ABI
bool __arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier,
__barrier_phase_t __old_phase);
_LIBCPP_EXPORTED_FROM_ABI
void __destroy_barrier_algorithm_base(__barrier_algorithm_base* __barrier);
template<class _CompletionF>
class __barrier_base {
ptrdiff_t __expected;
unique_ptr<__barrier_algorithm_base,
decltype(&__destroy_barrier_algorithm_base)> __base;
__atomic_base<ptrdiff_t> __expected_adjustment;
_CompletionF __completion;
__atomic_base<__barrier_phase_t> __phase;
public:
using arrival_token = __barrier_phase_t;
static constexpr ptrdiff_t max() noexcept {
return numeric_limits<ptrdiff_t>::max();
}
_LIBCPP_INLINE_VISIBILITY
__barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF())
: __expected(__expected), __base(__construct_barrier_algorithm_base(this->__expected),
&__destroy_barrier_algorithm_base),
__expected_adjustment(0), __completion(move(__completion)), __phase(0)
{
}
[[nodiscard]] _LIBCPP_INLINE_VISIBILITY
arrival_token arrive(ptrdiff_t update)
{
auto const __old_phase = __phase.load(memory_order_relaxed);
for(; update; --update)
if(__arrive_barrier_algorithm_base(__base.get(), __old_phase)) {
__completion();
__expected += __expected_adjustment.load(memory_order_relaxed);
__expected_adjustment.store(0, memory_order_relaxed);
__phase.store(__old_phase + 2, memory_order_release);
__phase.notify_all();
}
return __old_phase;
}
_LIBCPP_INLINE_VISIBILITY
void wait(arrival_token&& __old_phase) const
{
auto const __test_fn = [=]() -> bool {
return __phase.load(memory_order_acquire) != __old_phase;
};
__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
}
_LIBCPP_INLINE_VISIBILITY
void arrive_and_drop()
{
__expected_adjustment.fetch_sub(1, memory_order_relaxed);
(void)arrive(1);
}
};
#else
/*
The alternative implementation of __barrier_base is a central barrier.
Two versions of this algorithm are provided:
1. A fairly straightforward implementation of the litterature for the
general case where the completion function is not empty.
2. An optimized implementation that exploits 2's complement arithmetic
and well-defined overflow in atomic arithmetic, to handle the phase
roll-over for free.
*/
template<class _CompletionF>
class __barrier_base {
__atomic_base<ptrdiff_t> __expected;
__atomic_base<ptrdiff_t> __arrived;
_CompletionF __completion;
__atomic_base<bool> __phase;
public:
using arrival_token = bool;
static constexpr ptrdiff_t max() noexcept {
return numeric_limits<ptrdiff_t>::max();
}
_LIBCPP_INLINE_VISIBILITY
__barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF())
: __expected(__expected), __arrived(__expected), __completion(move(__completion)), __phase(false)
{
}
[[nodiscard]] _LIBCPP_INLINE_VISIBILITY
arrival_token arrive(ptrdiff_t update)
{
auto const __old_phase = __phase.load(memory_order_relaxed);
auto const __result = __arrived.fetch_sub(update, memory_order_acq_rel) - update;
auto const new_expected = __expected.load(memory_order_relaxed);
if(0 == __result) {
__completion();
__arrived.store(new_expected, memory_order_relaxed);
__phase.store(!__old_phase, memory_order_release);
__phase.notify_all();
}
return __old_phase;
}
_LIBCPP_INLINE_VISIBILITY
void wait(arrival_token&& __old_phase) const
{
__phase.wait(__old_phase, memory_order_acquire);
}
_LIBCPP_INLINE_VISIBILITY
void arrive_and_drop()
{
__expected.fetch_sub(1, memory_order_relaxed);
(void)arrive(1);
}
};
template<>
class __barrier_base<__empty_completion> {
static constexpr uint64_t __expected_unit = 1ull;
static constexpr uint64_t __arrived_unit = 1ull << 32;
static constexpr uint64_t __expected_mask = __arrived_unit - 1;
static constexpr uint64_t __phase_bit = 1ull << 63;
static constexpr uint64_t __arrived_mask = (__phase_bit - 1) & ~__expected_mask;
__atomic_base<uint64_t> __phase_arrived_expected;
static _LIBCPP_INLINE_VISIBILITY
constexpr uint64_t __init(ptrdiff_t __count) _NOEXCEPT
{
return ((uint64_t(1u << 31) - __count) << 32)
| (uint64_t(1u << 31) - __count);
}
public:
using arrival_token = uint64_t;
static constexpr ptrdiff_t max() noexcept {
return ptrdiff_t(1u << 31) - 1;
}
_LIBCPP_INLINE_VISIBILITY
explicit inline __barrier_base(ptrdiff_t __count, __empty_completion = __empty_completion())
: __phase_arrived_expected(__init(__count))
{
}
[[nodiscard]] inline _LIBCPP_INLINE_VISIBILITY
arrival_token arrive(ptrdiff_t update)
{
auto const __inc = __arrived_unit * update;
auto const __old = __phase_arrived_expected.fetch_add(__inc, memory_order_acq_rel);
if((__old ^ (__old + __inc)) & __phase_bit) {
__phase_arrived_expected.fetch_add((__old & __expected_mask) << 32, memory_order_relaxed);
__phase_arrived_expected.notify_all();
}
return __old & __phase_bit;
}
inline _LIBCPP_INLINE_VISIBILITY
void wait(arrival_token&& __phase) const
{
auto const __test_fn = [=]() -> bool {
uint64_t const __current = __phase_arrived_expected.load(memory_order_acquire);
return ((__current & __phase_bit) != __phase);
};
__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
}
inline _LIBCPP_INLINE_VISIBILITY
void arrive_and_drop()
{
__phase_arrived_expected.fetch_add(__expected_unit, memory_order_relaxed);
(void)arrive(1);
}
};
#endif //_LIBCPP_HAS_NO_TREE_BARRIER
template<class _CompletionF = __empty_completion>
class barrier {
__barrier_base<_CompletionF> __b;
public:
using arrival_token = typename __barrier_base<_CompletionF>::arrival_token;
static constexpr ptrdiff_t max() noexcept {
return __barrier_base<_CompletionF>::max();
}
_LIBCPP_INLINE_VISIBILITY
barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
: __b(__count, std::move(__completion)) {
}
barrier(barrier const&) = delete;
barrier& operator=(barrier const&) = delete;
[[nodiscard]] _LIBCPP_INLINE_VISIBILITY
arrival_token arrive(ptrdiff_t update = 1)
{
return __b.arrive(update);
}
_LIBCPP_INLINE_VISIBILITY
void wait(arrival_token&& __phase) const
{
__b.wait(std::move(__phase));
}
_LIBCPP_INLINE_VISIBILITY
void arrive_and_wait()
{
wait(arrive());
}
_LIBCPP_INLINE_VISIBILITY
void arrive_and_drop()
{
__b.arrive_and_drop();
}
};
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPP_BARRIER

104
libcxx/include/latch Normal file
View File

@@ -0,0 +1,104 @@
// -*- C++ -*-
//===--------------------------- latch -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_LATCH
#define _LIBCPP_LATCH
/*
latch synopsis
namespace std
{
class latch
{
public:
constexpr explicit latch(ptrdiff_t __expected);
~latch();
latch(const latch&) = delete;
latch& operator=(const latch&) = delete;
void count_down(ptrdiff_t __update = 1);
bool try_wait() const noexcept;
void wait() const;
void arrive_and_wait(ptrdiff_t __update = 1);
private:
ptrdiff_t __counter; // exposition only
};
}
*/
#include <__config>
#include <atomic>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
#ifdef _LIBCPP_HAS_NO_THREADS
# error <latch> is not supported on this single threaded system
#endif
#if _LIBCPP_STD_VER < 14
# error <latch> requires C++14 or later
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
class latch
{
__atomic_base<ptrdiff_t> __a;
public:
static constexpr ptrdiff_t max() noexcept {
return numeric_limits<ptrdiff_t>::max();
}
inline _LIBCPP_INLINE_VISIBILITY
constexpr explicit latch(ptrdiff_t __expected) : __a(__expected) { }
~latch() = default;
latch(const latch&) = delete;
latch& operator=(const latch&) = delete;
inline _LIBCPP_INLINE_VISIBILITY
void count_down(ptrdiff_t __update = 1)
{
auto const __old = __a.fetch_sub(__update, memory_order_release);
if(__old == __update)
__a.notify_all();
}
inline _LIBCPP_INLINE_VISIBILITY
bool try_wait() const noexcept
{
return 0 == __a.load(memory_order_acquire);
}
inline _LIBCPP_INLINE_VISIBILITY
void wait() const
{
auto const __test_fn = [=]() -> bool {
return try_wait();
};
__cxx_atomic_wait(&__a.__a_, __test_fn);
}
inline _LIBCPP_INLINE_VISIBILITY
void arrive_and_wait(ptrdiff_t __update = 1)
{
count_down(__update);
wait();
}
};
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPP_LATCH

View File

@@ -231,6 +231,10 @@ module std [system] {
header "atomic"
export *
}
module barrier {
header "barrier"
export *
}
module bit {
header "bit"
export *
@@ -334,6 +338,10 @@ module std [system] {
header "iterator"
export *
}
module latch {
header "latch"
export *
}
module limits {
header "limits"
export *
@@ -400,6 +408,10 @@ module std [system] {
header "scoped_allocator"
export *
}
module semaphore {
header "semaphore"
export *
}
module set {
header "set"
export initializer_list

233
libcxx/include/semaphore Normal file
View File

@@ -0,0 +1,233 @@
// -*- C++ -*-
//===--------------------------- semaphore --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_SEMAPHORE
#define _LIBCPP_SEMAPHORE
/*
semaphore synopsis
namespace std {
template<ptrdiff_t least_max_value = implementation-defined>
class counting_semaphore
{
public:
static constexpr ptrdiff_t max() noexcept;
constexpr explicit counting_semaphore(ptrdiff_t desired);
~counting_semaphore();
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete;
void release(ptrdiff_t update = 1);
void acquire();
bool try_acquire() noexcept;
template<class Rep, class Period>
bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
template<class Clock, class Duration>
bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
private:
ptrdiff_t counter; // exposition only
};
using binary_semaphore = counting_semaphore<1>;
}
*/
#include <__config>
#include <__threading_support>
#include <atomic>
#include <cassert>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
#ifdef _LIBCPP_HAS_NO_THREADS
# error <semaphore> is not supported on this single threaded system
#endif
#if _LIBCPP_STD_VER < 14
# error <semaphore> is requires C++14 or later
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
/*
__atomic_semaphore_base is the general-case implementation, to be used for
user-requested least-max values that exceed the OS implementation support
(incl. when the OS has no support of its own) and for binary semaphores.
It is a typical Dijsktra semaphore algorithm over atomics, wait and notify
functions. It avoids contention against users' own use of those facilities.
*/
class __atomic_semaphore_base
{
__atomic_base<ptrdiff_t> __a;
public:
_LIBCPP_INLINE_VISIBILITY
__atomic_semaphore_base(ptrdiff_t __count) : __a(__count)
{
}
_LIBCPP_INLINE_VISIBILITY
void release(ptrdiff_t __update = 1)
{
if(0 < __a.fetch_add(__update, memory_order_release))
;
else if(__update > 1)
__a.notify_all();
else
__a.notify_one();
}
_LIBCPP_INLINE_VISIBILITY
void acquire()
{
auto const __test_fn = [=]() -> bool {
auto __old = __a.load(memory_order_relaxed);
return (__old != 0) && __a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
};
__cxx_atomic_wait(&__a.__a_, __test_fn);
}
template <class Rep, class Period>
_LIBCPP_INLINE_VISIBILITY
bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time)
{
auto const __test_fn = [=]() -> bool {
auto __old = __a.load(memory_order_acquire);
while(1) {
if (__old == 0)
return false;
if(__a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
return true;
}
};
return __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy(), __rel_time);
}
};
#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
/*
__platform_semaphore_base a simple wrapper for the OS semaphore type. That
is, every call is routed to the OS in the most direct manner possible.
*/
class __platform_semaphore_base
{
__libcpp_semaphore_t __semaphore;
public:
_LIBCPP_INLINE_VISIBILITY
__platform_semaphore_base(ptrdiff_t __count) :
__semaphore()
{
__libcpp_semaphore_init(&__semaphore, __count);
}
_LIBCPP_INLINE_VISIBILITY
~__platform_semaphore_base() {
__libcpp_semaphore_destroy(&__semaphore);
}
_LIBCPP_INLINE_VISIBILITY
void release(ptrdiff_t __update)
{
for(; __update; --__update)
__libcpp_semaphore_post(&__semaphore);
}
_LIBCPP_INLINE_VISIBILITY
void acquire()
{
__libcpp_semaphore_wait(&__semaphore);
}
_LIBCPP_INLINE_VISIBILITY
bool try_acquire_for(chrono::nanoseconds __rel_time)
{
return __libcpp_semaphore_wait_timed(&__semaphore, __rel_time);
}
};
template<ptrdiff_t __least_max_value>
using __semaphore_base =
typename conditional<(__least_max_value > 1 && __least_max_value <= _LIBCPP_SEMAPHORE_MAX),
__platform_semaphore_base,
__atomic_semaphore_base>::type;
#else
template<ptrdiff_t __least_max_value>
using __semaphore_base =
__atomic_semaphore_base;
#endif //_LIBCPP_NO_NATIVE_SEMAPHORES
template<ptrdiff_t __least_max_value = _LIBCPP_SEMAPHORE_MAX>
class counting_semaphore
{
__semaphore_base<__least_max_value> __semaphore;
public:
static constexpr ptrdiff_t max() noexcept {
return __least_max_value;
}
_LIBCPP_INLINE_VISIBILITY
counting_semaphore(ptrdiff_t __count = 0) : __semaphore(__count) { }
~counting_semaphore() = default;
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete;
_LIBCPP_INLINE_VISIBILITY
void release(ptrdiff_t __update = 1)
{
__semaphore.release(__update);
}
_LIBCPP_INLINE_VISIBILITY
void acquire()
{
__semaphore.acquire();
}
template<class Rep, class Period>
_LIBCPP_INLINE_VISIBILITY
bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time)
{
return __semaphore.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time));
}
_LIBCPP_INLINE_VISIBILITY
bool try_acquire()
{
return try_acquire_for(chrono::nanoseconds::zero());
}
template <class Clock, class Duration>
_LIBCPP_INLINE_VISIBILITY
bool try_acquire_until(chrono::time_point<Clock, Duration> const& __abs_time)
{
auto const current = Clock::now();
if(current >= __abs_time)
return try_acquire();
else
return try_acquire_for(__abs_time - current);
}
};
using binary_semaphore = counting_semaphore<1>;
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPP_SEMAPHORE

View File

@@ -4,6 +4,8 @@ set(LIBCXX_LIB_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTOR
set(LIBCXX_SOURCES
algorithm.cpp
any.cpp
atomic.cpp
barrier.cpp
bind.cpp
charconv.cpp
chrono.cpp

189
libcxx/src/atomic.cpp Normal file
View File

@@ -0,0 +1,189 @@
//===------------------------- atomic.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <__config>
#ifndef _LIBCPP_HAS_NO_THREADS
#include <climits>
#include <atomic>
#include <functional>
#include <iostream>
#ifdef __linux__
#include <unistd.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#else // <- Add other operating systems here
// Baseline needs no new headers
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef __linux__
static void __libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr,
__cxx_contention_t __val)
{
static constexpr timespec __timeout = { 2, 0 };
syscall(SYS_futex, __ptr, FUTEX_WAIT_PRIVATE, __val, &__timeout, 0, 0);
}
static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr,
bool __notify_one)
{
syscall(SYS_futex, __ptr, FUTEX_WAKE_PRIVATE, __notify_one ? 1 : INT_MAX, 0, 0, 0);
}
#elif defined(__APPLE__) && defined(_LIBCPP_USE_ULOCK)
extern "C" int __ulock_wait(uint32_t operation, void *addr, uint64_t value,
uint32_t timeout); /* timeout is specified in microseconds */
extern "C" int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
#define UL_COMPARE_AND_WAIT 1
#define ULF_WAKE_ALL 0x00000100
static void __libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr,
__cxx_contention_t __val)
{
__ulock_wait(UL_COMPARE_AND_WAIT,
const_cast<__cxx_atomic_contention_t*>(__ptr), __val, 0);
}
static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr,
bool __notify_one)
{
__ulock_wake(UL_COMPARE_AND_WAIT | (__notify_one ? 0 : ULF_WAKE_ALL),
const_cast<__cxx_atomic_contention_t*>(__ptr), 0);
}
#else // <- Add other operating systems here
// Baseline is just a timed backoff
static void __libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr,
__cxx_contention_t __val)
{
__libcpp_thread_poll_with_backoff([=]() -> bool {
return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__ptr, memory_order_relaxed), __val);
}, __libcpp_timed_backoff_policy());
}
static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile*, bool) { }
#endif // __linux__
static constexpr size_t __libcpp_contention_table_size = (1 << 8); /* < there's no magic in this number */
struct alignas(64) /* aim to avoid false sharing */ __libcpp_contention_table_entry
{
__cxx_atomic_contention_t __contention_state;
__cxx_atomic_contention_t __platform_state;
inline constexpr __libcpp_contention_table_entry() :
__contention_state(0), __platform_state(0) { }
};
static __libcpp_contention_table_entry __libcpp_contention_table[ __libcpp_contention_table_size ];
static hash<void const volatile*> __libcpp_contention_hasher;
static __libcpp_contention_table_entry* __libcpp_contention_state(void const volatile * p)
{
return &__libcpp_contention_table[__libcpp_contention_hasher(p) & (__libcpp_contention_table_size - 1)];
}
/* Given an atomic to track contention and an atomic to actually wait on, which may be
the same atomic, we try to detect contention to avoid spuriously calling the platform. */
static void __libcpp_contention_notify(__cxx_atomic_contention_t volatile* __contention_state,
__cxx_atomic_contention_t const volatile* __platform_state,
bool __notify_one)
{
if(0 != __cxx_atomic_load(__contention_state, memory_order_seq_cst))
// We only call 'wake' if we consumed a contention bit here.
__libcpp_platform_wake_by_address(__platform_state, __notify_one);
}
static __cxx_contention_t __libcpp_contention_monitor_for_wait(__cxx_atomic_contention_t volatile* __contention_state,
__cxx_atomic_contention_t const volatile* __platform_state)
{
// We will monitor this value.
return __cxx_atomic_load(__platform_state, memory_order_acquire);
}
static void __libcpp_contention_wait(__cxx_atomic_contention_t volatile* __contention_state,
__cxx_atomic_contention_t const volatile* __platform_state,
__cxx_contention_t __old_value)
{
__cxx_atomic_fetch_add(__contention_state, __cxx_contention_t(1), memory_order_seq_cst);
// We sleep as long as the monitored value hasn't changed.
__libcpp_platform_wait_on_address(__platform_state, __old_value);
__cxx_atomic_fetch_sub(__contention_state, __cxx_contention_t(1), memory_order_release);
}
/* When the incoming atomic is the wrong size for the platform wait size, need to
launder the value sequence through an atomic from our table. */
static void __libcpp_atomic_notify(void const volatile* __location)
{
auto const __entry = __libcpp_contention_state(__location);
// The value sequence laundering happens on the next line below.
__cxx_atomic_fetch_add(&__entry->__platform_state, __cxx_contention_t(1), memory_order_release);
__libcpp_contention_notify(&__entry->__contention_state,
&__entry->__platform_state,
false /* when laundering, we can't handle notify_one */);
}
_LIBCPP_EXPORTED_FROM_ABI
void __cxx_atomic_notify_one(void const volatile* __location)
{ __libcpp_atomic_notify(__location); }
_LIBCPP_EXPORTED_FROM_ABI
void __cxx_atomic_notify_all(void const volatile* __location)
{ __libcpp_atomic_notify(__location); }
_LIBCPP_EXPORTED_FROM_ABI
__cxx_contention_t __libcpp_atomic_monitor(void const volatile* __location)
{
auto const __entry = __libcpp_contention_state(__location);
return __libcpp_contention_monitor_for_wait(&__entry->__contention_state, &__entry->__platform_state);
}
_LIBCPP_EXPORTED_FROM_ABI
void __libcpp_atomic_wait(void const volatile* __location, __cxx_contention_t __old_value)
{
auto const __entry = __libcpp_contention_state(__location);
__libcpp_contention_wait(&__entry->__contention_state, &__entry->__platform_state, __old_value);
}
/* When the incoming atomic happens to be the platform wait size, we still need to use the
table for the contention detection, but we can use the atomic directly for the wait. */
_LIBCPP_EXPORTED_FROM_ABI
void __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile* __location)
{
__libcpp_contention_notify(&__libcpp_contention_state(__location)->__contention_state, __location, true);
}
_LIBCPP_EXPORTED_FROM_ABI
void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile* __location)
{
__libcpp_contention_notify(&__libcpp_contention_state(__location)->__contention_state, __location, false);
}
_LIBCPP_EXPORTED_FROM_ABI
__cxx_contention_t __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile* __location)
{
return __libcpp_contention_monitor_for_wait(&__libcpp_contention_state(__location)->__contention_state, __location);
}
_LIBCPP_EXPORTED_FROM_ABI
void __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile* __location, __cxx_contention_t __old_value)
{
__libcpp_contention_wait(&__libcpp_contention_state(__location)->__contention_state, __location, __old_value);
}
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPP_HAS_NO_THREADS

95
libcxx/src/barrier.cpp Normal file
View File

@@ -0,0 +1,95 @@
//===------------------------- barrier.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <__config>
#ifndef _LIBCPP_HAS_NO_THREADS
#include <barrier>
#include <thread>
_LIBCPP_BEGIN_NAMESPACE_STD
#if !defined(_LIBCPP_HAS_NO_TREE_BARRIER) && (_LIBCPP_STD_VER > 11)
class __barrier_algorithm_base {
public:
struct alignas(64) /* naturally-align the heap state */ __state_t
{
struct {
__atomic_base<__barrier_phase_t> __phase = ATOMIC_VAR_INIT(0);
} __tickets[64];
};
ptrdiff_t& __expected;
unique_ptr<__state_t[]> __state;
_LIBCPP_HIDDEN
__barrier_algorithm_base(ptrdiff_t& __expected)
: __expected(__expected), __state(new __barrier_algorithm_base::__state_t[(__expected + 1) >> 1])
{
}
_LIBCPP_HIDDEN
bool __arrive(__barrier_phase_t __old_phase)
{
__barrier_phase_t const __half_step = __old_phase + 1,
__full_step = __old_phase + 2;
size_t __current_expected = __expected,
__current = hash<thread::id>()(this_thread::get_id()) % ((__expected + 1) >> 1);
for(int __round = 0;; ++__round) {
if(__current_expected <= 1)
return true;
size_t const __end_node = ((__current_expected + 1) >> 1),
__last_node = __end_node - 1;
for(;;++__current) {
if(__current == __end_node)
__current = 0;
__barrier_phase_t expect = __old_phase;
if(__current == __last_node && (__current_expected & 1))
{
if(__state[__current].__tickets[__round].__phase.compare_exchange_strong(expect, __full_step, memory_order_acq_rel))
break; // I'm 1 in 1, go to next __round
}
else if(__state[__current].__tickets[__round].__phase.compare_exchange_strong(expect, __half_step, memory_order_acq_rel))
{
return false; // I'm 1 in 2, done with arrival
}
else if(expect == __half_step)
{
if(__state[__current].__tickets[__round].__phase.compare_exchange_strong(expect, __full_step, memory_order_acq_rel))
break; // I'm 2 in 2, go to next __round
}
}
__current_expected = __last_node + 1;
__current >>= 1;
}
}
};
_LIBCPP_EXPORTED_FROM_ABI
__barrier_algorithm_base * __construct_barrier_algorithm_base(ptrdiff_t& __expected)
{
return new __barrier_algorithm_base(__expected);
}
_LIBCPP_EXPORTED_FROM_ABI
bool __arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier,
__barrier_phase_t __old_phase)
{
return __barrier->__arrive(__old_phase);
}
_LIBCPP_EXPORTED_FROM_ABI
void __destroy_barrier_algorithm_base(__barrier_algorithm_base* __barrier)
{
delete __barrier;
}
#endif //!defined(_LIBCPP_HAS_NO_TREE_BARRIER) && (_LIBCPP_STD_VER >= 11)
_LIBCPP_END_NAMESPACE_STD
#endif //_LIBCPP_HAS_NO_THREADS

View File

@@ -46,6 +46,24 @@
#endif
#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101500
#define _LIBCPP_USE_ULOCK
#endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 130000
#define _LIBCPP_USE_ULOCK
#endif
#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 130000
#define _LIBCPP_USE_ULOCK
#endif
#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 60000
#define _LIBCPP_USE_ULOCK
#endif
#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
#endif // __APPLE__
#endif // _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H

View File

@@ -25,6 +25,9 @@
#include <array>
#ifndef _LIBCPP_HAS_NO_THREADS
#include <atomic>
#include <latch>
#include <barrier>
#include <semaphore>
#endif
#include <bit>
#include <bitset>

View File

@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// XFAIL: c++98, c++03
// <atomic>
#include <atomic>
#include <type_traits>
#include <cassert>
#include <thread>
#include "test_macros.h"
#include "../atomics.types.operations.req/atomic_helpers.h"
template <class T>
struct TestFn {
void operator()() const {
typedef std::atomic<T> A;
A t;
std::atomic_init(&t, T(1));
assert(std::atomic_load(&t) == T(1));
std::atomic_wait(&t, T(0));
std::thread t_([&](){
std::atomic_store(&t, T(3));
std::atomic_notify_one(&t);
});
std::atomic_wait(&t, T(1));
t_.join();
volatile A vt;
std::atomic_init(&vt, T(2));
assert(std::atomic_load(&vt) == T(2));
std::atomic_wait(&vt, T(1));
std::thread t2_([&](){
std::atomic_store(&vt, T(4));
std::atomic_notify_one(&vt);
});
std::atomic_wait(&vt, T(2));
t2_.join();
}
};
int main(int, char**)
{
TestEachAtomicType<TestFn>()();
return 0;
}

View File

@@ -0,0 +1,125 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <atomic>
// Test nested types
// template <class T>
// class atomic
// {
// public:
// typedef T value_type;
// };
#include <atomic>
#include <type_traits>
#include <thread>
#include <chrono>
#if TEST_STD_VER >= 20
# include <memory>
#endif
#include "test_macros.h"
template <class A>
void
test_atomic()
{
A a;
#if TEST_STD_VER >= 17
static_assert((std::is_same<typename A::value_type, decltype(a.load())>::value), "");
#endif
}
template <class T>
void
test()
{
using A = std::atomic<T>;
#if TEST_STD_VER >= 17
static_assert((std::is_same<typename A::value_type, T>::value), "");
#endif
test_atomic<A>();
}
struct TriviallyCopyable {
int i_;
};
int main(int, char**)
{
test<bool> ();
test<char> ();
test<signed char> ();
test<unsigned char> ();
test<short> ();
test<unsigned short> ();
test<int> ();
test<unsigned int> ();
test<long> ();
test<unsigned long> ();
test<long long> ();
test<unsigned long long> ();
test<char16_t> ();
test<char32_t> ();
test<wchar_t> ();
test<int_least8_t> ();
test<uint_least8_t> ();
test<int_least16_t> ();
test<uint_least16_t> ();
test<int_least32_t> ();
test<uint_least32_t> ();
test<int_least64_t> ();
test<uint_least64_t> ();
test<int_fast8_t> ();
test<uint_fast8_t> ();
test<int_fast16_t> ();
test<uint_fast16_t> ();
test<int_fast32_t> ();
test<uint_fast32_t> ();
test<int_fast64_t> ();
test<uint_fast64_t> ();
test< int8_t> ();
test<uint8_t> ();
test< int16_t> ();
test<uint16_t> ();
test< int32_t> ();
test<uint32_t> ();
test< int64_t> ();
test<uint64_t> ();
test<intptr_t> ();
test<uintptr_t> ();
test<size_t> ();
test<ptrdiff_t> ();
test<intmax_t> ();
test<uintmax_t> ();
test<uintmax_t> ();
test<uintmax_t> ();
test<TriviallyCopyable>();
test<std::thread::id>();
test<std::chrono::nanoseconds>();
test<float>();
#if TEST_STD_VER >= 20
test_atomic<std::atomic_signed_lock_free>();
test_atomic<std::atomic_unsigned_lock_free>();
/*
test<std::shared_ptr<int>>();
*/
#endif
return 0;
}

View File

@@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <barrier>
#include <barrier>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::barrier<> b(2);
auto tok = b.arrive();
std::thread t([&](){
(void)b.arrive();
});
b.wait(std::move(tok));
t.join();
auto tok2 = b.arrive(2);
b.wait(std::move(tok2));
return 0;
}

View File

@@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <barrier>
#include <barrier>
#include <thread>
#include <cassert>
#include "test_macros.h"
int main(int, char**)
{
std::barrier<> b(2);
std::thread t([&](){
b.arrive_and_drop();
});
b.arrive_and_wait();
b.arrive_and_wait();
t.join();
return 0;
}

View File

@@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <barrier>
#include <barrier>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::barrier<> b(2);
std::thread t([&](){
for(int i = 0; i < 10; ++i)
b.arrive_and_wait();
});
for(int i = 0; i < 10; ++i)
b.arrive_and_wait();
t.join();
return 0;
}

View File

@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <barrier>
#include <barrier>
#include <thread>
#include <cassert>
#include "test_macros.h"
int main(int, char**)
{
int x = 0;
auto comp = [&]() { x += 1; };
std::barrier<decltype(comp)> b(2, comp);
std::thread t([&](){
for(int i = 0; i < 10; ++i)
b.arrive_and_wait();
});
for(int i = 0; i < 10; ++i)
b.arrive_and_wait();
assert(x == 10);
t.join();
return 0;
}

View File

@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <barrier>
#include <barrier>
#include <thread>
#include <cassert>
#include "test_macros.h"
int main(int, char**)
{
static_assert(std::barrier<>::max() > 0, "");
auto l = [](){};
static_assert(std::barrier<decltype(l)>::max() > 0, "");
return 0;
}

View File

@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <barrier>
#include <barrier>
#include "test_macros.h"
#ifndef _LIBCPP_VERSION
#error _LIBCPP_VERSION not defined
#endif
int main(int, char**)
{
return 0;
}

View File

@@ -0,0 +1,30 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <latch>
#include <latch>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::latch l(2);
std::thread t([&](){
l.arrive_and_wait();
});
l.arrive_and_wait();
t.join();
return 0;
}

View File

@@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <latch>
#include <latch>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::latch l(2);
l.count_down();
std::thread t([&](){
l.count_down();
});
l.wait();
t.join();
return 0;
}

View File

@@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <latch>
#include <latch>
#include <cassert>
#include "test_macros.h"
int main(int, char**)
{
static_assert(std::latch::max() > 0, "");
return 0;
}

View File

@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <latch>
#include <latch>
#include <cassert>
#include "test_macros.h"
int main(int, char**)
{
std::latch l(1);
l.count_down();
bool const b = l.try_wait();
assert(b);
return 0;
}

View File

@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <latch>
#include <latch>
#include "test_macros.h"
#ifndef _LIBCPP_VERSION
#error _LIBCPP_VERSION not defined
#endif
int main(int, char**)
{
return 0;
}

View File

@@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::counting_semaphore<> s(2);
std::thread t([&](){
s.acquire();
});
t.join();
s.acquire();
return 0;
}

View File

@@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include <chrono>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::binary_semaphore s(1);
auto l = [&](){
for(int i = 0; i < 1024; ++i) {
s.acquire();
std::this_thread::sleep_for(std::chrono::microseconds(1));
s.release();
}
};
std::thread t(l);
l();
t.join();
return 0;
}

View File

@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
static_assert(std::counting_semaphore<>::max() > 0, "");
static_assert(std::counting_semaphore<1>::max() >= 1, "");
static_assert(std::counting_semaphore<std::numeric_limits<int>::max()>::max() >= 1, "");
static_assert(std::counting_semaphore<std::numeric_limits<unsigned>::max()>::max() >= 1, "");
static_assert(std::counting_semaphore<std::numeric_limits<ptrdiff_t>::max()>::max() >= 1, "");
static_assert(std::counting_semaphore<1>::max() == std::binary_semaphore::max(), "");
return 0;
}

View File

@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::counting_semaphore<> s(0);
s.release();
s.acquire();
std::thread t([&](){
s.acquire();
});
s.release(2);
t.join();
s.acquire();
return 0;
}

View File

@@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include <thread>
#include <chrono>
#include "test_macros.h"
int main(int, char**)
{
auto const start = std::chrono::steady_clock::now();
std::counting_semaphore<> s(0);
assert(!s.try_acquire_until(start + std::chrono::milliseconds(250)));
assert(!s.try_acquire_for(std::chrono::milliseconds(250)));
std::thread t([&](){
std::this_thread::sleep_for(std::chrono::milliseconds(250));
s.release();
std::this_thread::sleep_for(std::chrono::milliseconds(250));
s.release();
});
assert(s.try_acquire_until(start + std::chrono::seconds(2)));
assert(s.try_acquire_for(std::chrono::seconds(2)));
t.join();
auto const end = std::chrono::steady_clock::now();
assert(end - start < std::chrono::seconds(10));
return 0;
}

View File

@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include <thread>
#include "test_macros.h"
int main(int, char**)
{
std::counting_semaphore<> s(1);
assert(s.try_acquire());
s.release();
assert(s.try_acquire());
s.release(2);
std::thread t([&](){
assert(s.try_acquire());
});
t.join();
assert(s.try_acquire());
return 0;
}

View File

@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// UNSUPPORTED: c++98, c++03, c++11
// <semaphore>
#include <semaphore>
#include "test_macros.h"
#ifndef _LIBCPP_VERSION
#error _LIBCPP_VERSION not defined
#endif
int main(int, char**)
{
return 0;
}

View File

@@ -169,7 +169,7 @@
<tr><td><a href="https://wg21.link/P1004">P1004</a></td><td>LWG</td><td>Making std::vector constexpr</td><td>Cologne</td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/P1035">P1035</a></td><td>LWG</td><td>Input Range Adaptors</td><td>Cologne</td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/P1065">P1065</a></td><td>LWG</td><td>Constexpr INVOKE</td><td>Cologne</td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/P1135">P1135</a></td><td>LWG</td><td>The C++20 Synchronization Library</td><td>Cologne</td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/P1135">P1135</a></td><td>LWG</td><td>The C++20 Synchronization Library</td><td>Cologne</td><td>Complete</td><td></td></tr>
<tr><td><a href="https://wg21.link/P1207">P1207</a></td><td>LWG</td><td>Movability of Single-pass Iterators</td><td>Cologne</td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/P1208">P1208</a></td><td>LWG</td><td>Adopt source_location for C++20</td><td>Cologne</td><td></td><td></td></tr>
<tr><td><a href="https://wg21.link/P1355">P1355</a></td><td>LWG</td><td>Exposing a narrow contract for ceil2</td><td>Cologne</td><td>Complete</td><td>9.0</td></tr>