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 class __barrier_algorithm_base
{
16 struct alignas(64) /* naturally-align the heap state */ __state_t
{
18 atomic
<__barrier_phase_t
> __phase
{0};
22 ptrdiff_t& __expected_
;
23 unique_ptr
<__state_t
[]> __state_
;
25 _LIBCPP_HIDDEN
__barrier_algorithm_base(ptrdiff_t& __expected
) : __expected_(__expected
) {
26 size_t const __count
= (__expected
+ 1) >> 1;
27 __state_
= unique_ptr
<__state_t
[]>(new __state_t
[__count
]);
29 _LIBCPP_HIDDEN
bool __arrive(__barrier_phase_t __old_phase
) {
30 __barrier_phase_t
const __half_step
= __old_phase
+ 1, __full_step
= __old_phase
+ 2;
31 size_t __current_expected
= __expected_
,
32 __current
= hash
<thread::id
>()(this_thread::get_id()) % ((__expected_
+ 1) >> 1);
33 for (int __round
= 0;; ++__round
) {
34 if (__current_expected
<= 1)
36 size_t const __end_node
= ((__current_expected
+ 1) >> 1), __last_node
= __end_node
- 1;
37 for (;; ++__current
) {
38 if (__current
== __end_node
)
40 __barrier_phase_t expect
= __old_phase
;
41 if (__current
== __last_node
&& (__current_expected
& 1)) {
42 if (__state_
[__current
].__tickets
[__round
].__phase
.compare_exchange_strong(
43 expect
, __full_step
, memory_order_acq_rel
))
44 break; // I'm 1 in 1, go to next __round
45 } else if (__state_
[__current
].__tickets
[__round
].__phase
.compare_exchange_strong(
46 expect
, __half_step
, memory_order_acq_rel
)) {
47 return false; // I'm 1 in 2, done with arrival
48 } else if (expect
== __half_step
) {
49 if (__state_
[__current
].__tickets
[__round
].__phase
.compare_exchange_strong(
50 expect
, __full_step
, memory_order_acq_rel
))
51 break; // I'm 2 in 2, go to next __round
54 __current_expected
= __last_node
+ 1;
60 _LIBCPP_EXPORTED_FROM_ABI __barrier_algorithm_base
* __construct_barrier_algorithm_base(ptrdiff_t& __expected
) {
61 return new __barrier_algorithm_base(__expected
);
63 _LIBCPP_EXPORTED_FROM_ABI
bool
64 __arrive_barrier_algorithm_base(__barrier_algorithm_base
* __barrier
, __barrier_phase_t __old_phase
) noexcept
{
65 return __barrier
->__arrive(__old_phase
);
67 _LIBCPP_EXPORTED_FROM_ABI
void __destroy_barrier_algorithm_base(__barrier_algorithm_base
* __barrier
) noexcept
{
71 _LIBCPP_END_NAMESPACE_STD