1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
12 _LIBCPP_BEGIN_NAMESPACE_STD
14 #if !defined(_LIBCPP_HAS_NO_TREE_BARRIER)
16 class __barrier_algorithm_base
{
18 struct alignas(64) /* naturally-align the heap state */ __state_t
{
20 atomic
<__barrier_phase_t
> __phase
{0};
24 ptrdiff_t& __expected_
;
25 unique_ptr
<__state_t
[]> __state_
;
27 _LIBCPP_HIDDEN
__barrier_algorithm_base(ptrdiff_t& __expected
) : __expected_(__expected
) {
28 size_t const __count
= (__expected
+ 1) >> 1;
29 __state_
= unique_ptr
<__state_t
[]>(new __state_t
[__count
]);
31 _LIBCPP_HIDDEN
bool __arrive(__barrier_phase_t __old_phase
) {
32 __barrier_phase_t
const __half_step
= __old_phase
+ 1, __full_step
= __old_phase
+ 2;
33 size_t __current_expected
= __expected_
,
34 __current
= hash
<thread::id
>()(this_thread::get_id()) % ((__expected_
+ 1) >> 1);
35 for (int __round
= 0;; ++__round
) {
36 if (__current_expected
<= 1)
38 size_t const __end_node
= ((__current_expected
+ 1) >> 1), __last_node
= __end_node
- 1;
39 for (;; ++__current
) {
40 if (__current
== __end_node
)
42 __barrier_phase_t expect
= __old_phase
;
43 if (__current
== __last_node
&& (__current_expected
& 1)) {
44 if (__state_
[__current
].__tickets
[__round
].__phase
.compare_exchange_strong(
45 expect
, __full_step
, memory_order_acq_rel
))
46 break; // I'm 1 in 1, go to next __round
47 } else if (__state_
[__current
].__tickets
[__round
].__phase
.compare_exchange_strong(
48 expect
, __half_step
, memory_order_acq_rel
)) {
49 return false; // I'm 1 in 2, done with arrival
50 } else if (expect
== __half_step
) {
51 if (__state_
[__current
].__tickets
[__round
].__phase
.compare_exchange_strong(
52 expect
, __full_step
, memory_order_acq_rel
))
53 break; // I'm 2 in 2, go to next __round
56 __current_expected
= __last_node
+ 1;
62 _LIBCPP_EXPORTED_FROM_ABI __barrier_algorithm_base
* __construct_barrier_algorithm_base(ptrdiff_t& __expected
) {
63 return new __barrier_algorithm_base(__expected
);
65 _LIBCPP_EXPORTED_FROM_ABI
bool
66 __arrive_barrier_algorithm_base(__barrier_algorithm_base
* __barrier
, __barrier_phase_t __old_phase
) noexcept
{
67 return __barrier
->__arrive(__old_phase
);
69 _LIBCPP_EXPORTED_FROM_ABI
void __destroy_barrier_algorithm_base(__barrier_algorithm_base
* __barrier
) noexcept
{
73 #endif // !defined(_LIBCPP_HAS_NO_TREE_BARRIER)
75 _LIBCPP_END_NAMESPACE_STD