317 changes: 311 additions & 6 deletions libcxx/include/atomic

Large diffs are not rendered by default.

322 changes: 322 additions & 0 deletions libcxx/include/barrier
Original file line number Diff line number Diff line change
@@ -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_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI
__barrier_algorithm_base* __construct_barrier_algorithm_base(ptrdiff_t& __expected);

_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI
bool __arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier,
__barrier_phase_t __old_phase);

_LIBCPP_AVAILABILITY_SYNC _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 changes: 104 additions & 0 deletions libcxx/include/latch
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ module std [system] {
header "atomic"
export *
}
module barrier {
header "barrier"
export *
}
module bit {
header "bit"
export *
Expand Down Expand Up @@ -334,6 +338,10 @@ module std [system] {
header "iterator"
export *
}
module latch {
header "latch"
export *
}
module limits {
header "limits"
export *
Expand Down Expand Up @@ -400,6 +408,10 @@ module std [system] {
header "scoped_allocator"
export *
}
module semaphore {
header "semaphore"
export *
}
module set {
header "set"
export initializer_list
Expand Down
233 changes: 233 additions & 0 deletions libcxx/include/semaphore
Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions libcxx/lib/abi/CHANGELOG.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ Afterwards the ABI list should be updated to include the new changes.

New entries should be added directly below the "Version" header.

------------
Version 10.0
------------

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

libc++ now implements P1135R6 (The C++20 Synchronization Library), which
adds a few symbols to the dylib. This is backwards-compatible since we're
just adding new symbols.

x86_64-unknown-linux-gnu
------------------------
TODO

x86_64-apple-apple-darwin
-------------------------
Symbol added: __ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEEx
Symbol added: __ZNSt3__120__libcpp_atomic_waitEPVKvx
Symbol added: __ZNSt3__123__cxx_atomic_notify_allEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE
Symbol added: __ZNSt3__123__cxx_atomic_notify_allEPVKv
Symbol added: __ZNSt3__123__cxx_atomic_notify_oneEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE
Symbol added: __ZNSt3__123__cxx_atomic_notify_oneEPVKv
Symbol added: __ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE
Symbol added: __ZNSt3__123__libcpp_atomic_monitorEPVKv
Symbol added: __ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh
Symbol added: __ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE
Symbol added: __ZNSt3__134__construct_barrier_algorithm_baseERl

-----------
Version 9.0
-----------
Expand Down
11 changes: 11 additions & 0 deletions libcxx/lib/abi/x86_64-apple-darwin.v1.abilist
Original file line number Diff line number Diff line change
Expand Up @@ -2420,3 +2420,14 @@
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZTINSt3__14__fs10filesystem16filesystem_errorE', 'size': 0}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZTSNSt3__14__fs10filesystem16filesystem_errorE', 'size': 0}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZTVNSt3__14__fs10filesystem16filesystem_errorE', 'size': 0}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEEx'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__120__libcpp_atomic_waitEPVKvx'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__123__cxx_atomic_notify_allEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__123__cxx_atomic_notify_allEPVKv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__123__cxx_atomic_notify_oneEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__123__cxx_atomic_notify_oneEPVKv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl'}
11 changes: 11 additions & 0 deletions libcxx/lib/abi/x86_64-apple-darwin.v2.abilist
Original file line number Diff line number Diff line change
Expand Up @@ -2376,3 +2376,14 @@
{'is_defined': True, 'name': '___dynamic_cast', 'type': 'I'}
{'is_defined': False, 'name': '___gxx_personality_v0', 'type': 'U'}
{'is_defined': True, 'name': '___gxx_personality_v0', 'type': 'I'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__220__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEEx'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__220__libcpp_atomic_waitEPVKvx'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__223__cxx_atomic_notify_allEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__223__cxx_atomic_notify_allEPVKv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__223__cxx_atomic_notify_oneEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__223__cxx_atomic_notify_oneEPVKv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__223__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__223__libcpp_atomic_monitorEPVKv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__231__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__232__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__234__construct_barrier_algorithm_baseERl'}
2 changes: 2 additions & 0 deletions libcxx/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
189 changes: 189 additions & 0 deletions libcxx/src/atomic.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 95 additions & 0 deletions libcxx/src/barrier.cpp
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions libcxx/src/include/apple_availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions libcxx/test/libcxx/double_include.sh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include <array>
#ifndef _LIBCPP_HAS_NO_THREADS
#include <atomic>
#include <latch>
#include <barrier>
#include <semaphore>
#endif
#include <bit>
#include <bitset>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
125 changes: 125 additions & 0 deletions libcxx/test/std/atomics/types.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
42 changes: 42 additions & 0 deletions libcxx/test/std/thread/thread.barrier/arrive.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
41 changes: 41 additions & 0 deletions libcxx/test/std/thread/thread.barrier/arrive_and_drop.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
41 changes: 41 additions & 0 deletions libcxx/test/std/thread/thread.barrier/arrive_and_wait.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
46 changes: 46 additions & 0 deletions libcxx/test/std/thread/thread.barrier/completion.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
26 changes: 26 additions & 0 deletions libcxx/test/std/thread/thread.barrier/max.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
25 changes: 25 additions & 0 deletions libcxx/test/std/thread/thread.barrier/version.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
39 changes: 39 additions & 0 deletions libcxx/test/std/thread/thread.latch/arrive_and_wait.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
40 changes: 40 additions & 0 deletions libcxx/test/std/thread/thread.latch/count_down.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
23 changes: 23 additions & 0 deletions libcxx/test/std/thread/thread.latch/max.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
37 changes: 37 additions & 0 deletions libcxx/test/std/thread/thread.latch/try_wait.pass.cpp
Original file line number Diff line number Diff line change
@@ -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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
25 changes: 25 additions & 0 deletions libcxx/test/std/thread/thread.latch/version.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
40 changes: 40 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/acquire.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
47 changes: 47 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/binary.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
28 changes: 28 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/max.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
43 changes: 43 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/release.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
53 changes: 53 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/timed.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
43 changes: 43 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/try_acquire.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// 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

// This test requires the dylib support introduced in D68480
// XFAIL: with_system_cxx_lib=macosx10.15
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9

// <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;
}
25 changes: 25 additions & 0 deletions libcxx/test/std/thread/thread.semaphore/version.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion libcxx/www/cxx2a_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ <h3>Paper Status</h3>
<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>
Expand Down