2020-02-18 09:58:34 -05:00
|
|
|
// -*- C++ -*-
|
2021-11-17 16:25:01 -05:00
|
|
|
//===----------------------------------------------------------------------===//
|
2020-02-18 09:58:34 -05:00
|
|
|
//
|
|
|
|
// 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>
|
2024-07-31 16:53:09 -05:00
|
|
|
class barrier // since C++20
|
2020-02-18 09:58:34 -05:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
using arrival_token = see below;
|
|
|
|
|
2020-12-06 15:36:18 +01:00
|
|
|
static constexpr ptrdiff_t max() noexcept;
|
|
|
|
|
2020-02-18 09:58:34 -05:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2024-12-21 13:01:48 +01:00
|
|
|
#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
|
2025-04-09 15:00:46 +02:00
|
|
|
# include <__cxx03/__config>
|
2024-12-21 13:01:48 +01:00
|
|
|
#else
|
2024-12-10 16:02:12 +01:00
|
|
|
# include <__config>
|
|
|
|
|
|
|
|
# if _LIBCPP_HAS_THREADS
|
|
|
|
|
|
|
|
# include <__assert>
|
|
|
|
# include <__atomic/atomic.h>
|
|
|
|
# include <__atomic/memory_order.h>
|
|
|
|
# include <__cstddef/ptrdiff_t.h>
|
|
|
|
# include <__memory/unique_ptr.h>
|
|
|
|
# include <__thread/poll_with_backoff.h>
|
|
|
|
# include <__thread/timed_backoff_policy.h>
|
|
|
|
# include <__utility/move.h>
|
|
|
|
# include <cstdint>
|
|
|
|
# include <limits>
|
|
|
|
# include <version>
|
|
|
|
|
|
|
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
|
|
# pragma GCC system_header
|
|
|
|
# endif
|
2020-02-18 09:58:34 -05:00
|
|
|
|
2020-12-02 18:55:01 -05:00
|
|
|
_LIBCPP_PUSH_MACROS
|
2024-12-10 16:02:12 +01:00
|
|
|
# include <__undef_macros>
|
2020-12-02 18:55:01 -05:00
|
|
|
|
2024-12-10 16:02:12 +01:00
|
|
|
# if _LIBCPP_STD_VER >= 20
|
2020-02-18 09:58:34 -05:00
|
|
|
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
|
|
|
|
struct __empty_completion {
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI void operator()() noexcept {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2025-01-08 17:12:59 +01:00
|
|
|
using __barrier_phase_t _LIBCPP_NODEBUG = uint8_t;
|
2020-02-18 09:58:34 -05:00
|
|
|
|
|
|
|
class __barrier_algorithm_base;
|
|
|
|
|
2020-02-24 10:08:41 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __barrier_algorithm_base*
|
2020-02-18 09:58:34 -05:00
|
|
|
__construct_barrier_algorithm_base(ptrdiff_t& __expected);
|
|
|
|
|
2020-02-24 10:08:41 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI bool
|
2024-06-12 04:18:51 +02:00
|
|
|
__arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier, __barrier_phase_t __old_phase) noexcept;
|
2020-02-18 09:58:34 -05:00
|
|
|
|
2020-02-24 10:08:41 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
|
2024-06-12 04:18:51 +02:00
|
|
|
__destroy_barrier_algorithm_base(__barrier_algorithm_base* __barrier) noexcept;
|
2020-02-18 09:58:34 -05:00
|
|
|
|
|
|
|
template <class _CompletionF>
|
|
|
|
class __barrier_base {
|
2022-03-03 13:39:12 -05:00
|
|
|
ptrdiff_t __expected_;
|
|
|
|
unique_ptr<__barrier_algorithm_base, void (*)(__barrier_algorithm_base*)> __base_;
|
2024-11-20 00:35:14 +01:00
|
|
|
atomic<ptrdiff_t> __expected_adjustment_;
|
2022-03-03 13:39:12 -05:00
|
|
|
_CompletionF __completion_;
|
2024-11-20 00:35:14 +01:00
|
|
|
atomic<__barrier_phase_t> __phase_;
|
2020-02-18 09:58:34 -05:00
|
|
|
|
|
|
|
public:
|
|
|
|
using arrival_token = __barrier_phase_t;
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2023-01-23 10:27:14 +01:00
|
|
|
static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); }
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2020-02-24 10:09:29 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI
|
2020-02-18 09:58:34 -05:00
|
|
|
__barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF())
|
[libc++] Add custom clang-tidy checks
Reviewed By: #libc, ldionne
Spies: jwakely, beanz, smeenai, cfe-commits, tschuett, avogelsgesang, Mordante, sstefan1, libcxx-commits, ldionne, mgorny, arichardson, miyuki
Differential Revision: https://reviews.llvm.org/D131963
2022-08-13 22:33:12 +02:00
|
|
|
: __expected_(__expected),
|
|
|
|
__base_(std::__construct_barrier_algorithm_base(this->__expected_), &__destroy_barrier_algorithm_base),
|
2022-03-03 13:39:12 -05:00
|
|
|
__expected_adjustment_(0),
|
|
|
|
__completion_(std::move(__completion)),
|
|
|
|
__phase_(0) {}
|
2024-09-12 21:18:43 +02:00
|
|
|
[[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI arrival_token arrive(ptrdiff_t __update) {
|
2024-01-20 23:38:02 -08:00
|
|
|
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
|
2023-07-15 12:48:10 +02:00
|
|
|
__update <= __expected_, "update is greater than the expected count for the current barrier phase");
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2022-03-03 13:39:12 -05:00
|
|
|
auto const __old_phase = __phase_.load(memory_order_relaxed);
|
2022-07-08 18:17:26 +02:00
|
|
|
for (; __update; --__update)
|
2022-03-03 13:39:12 -05:00
|
|
|
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();
|
2020-02-18 09:58:34 -05:00
|
|
|
}
|
|
|
|
return __old_phase;
|
|
|
|
}
|
2020-02-24 10:09:29 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __old_phase) const {
|
2022-03-03 13:39:12 -05:00
|
|
|
auto const __test_fn = [this, __old_phase]() -> bool { return __phase_.load(memory_order_acquire) != __old_phase; };
|
[libc++] Add custom clang-tidy checks
Reviewed By: #libc, ldionne
Spies: jwakely, beanz, smeenai, cfe-commits, tschuett, avogelsgesang, Mordante, sstefan1, libcxx-commits, ldionne, mgorny, arichardson, miyuki
Differential Revision: https://reviews.llvm.org/D131963
2022-08-13 22:33:12 +02:00
|
|
|
std::__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
|
2020-02-18 09:58:34 -05:00
|
|
|
}
|
2020-02-24 10:09:29 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() {
|
2022-03-03 13:39:12 -05:00
|
|
|
__expected_adjustment_.fetch_sub(1, memory_order_relaxed);
|
2020-02-18 09:58:34 -05:00
|
|
|
(void)arrive(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class _CompletionF = __empty_completion>
|
2024-07-31 16:53:09 -05:00
|
|
|
class barrier {
|
2022-09-02 16:19:07 +02:00
|
|
|
__barrier_base<_CompletionF> __b_;
|
2020-02-18 09:58:34 -05:00
|
|
|
|
|
|
|
public:
|
|
|
|
using arrival_token = typename __barrier_base<_CompletionF>::arrival_token;
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2023-01-23 10:27:14 +01:00
|
|
|
static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return __barrier_base<_CompletionF>::max(); }
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2020-02-24 10:09:29 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC
|
2024-07-15 09:11:23 -05:00
|
|
|
_LIBCPP_HIDE_FROM_ABI explicit barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
|
2022-09-02 16:19:07 +02:00
|
|
|
: __b_(__count, std::move(__completion)) {
|
2024-01-20 23:38:02 -08:00
|
|
|
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
|
2023-07-15 12:48:10 +02:00
|
|
|
__count >= 0,
|
|
|
|
"barrier::barrier(ptrdiff_t, CompletionFunction): barrier cannot be initialized with a negative value");
|
2024-01-20 23:38:02 -08:00
|
|
|
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
|
2023-07-15 12:48:10 +02:00
|
|
|
__count <= max(),
|
|
|
|
"barrier::barrier(ptrdiff_t, CompletionFunction): barrier cannot be initialized with "
|
|
|
|
"a value greater than max()");
|
2020-02-18 09:58:34 -05:00
|
|
|
}
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2020-02-18 09:58:34 -05:00
|
|
|
barrier(barrier const&) = delete;
|
|
|
|
barrier& operator=(barrier const&) = delete;
|
2023-12-18 14:01:33 -05:00
|
|
|
|
2024-09-12 21:18:43 +02:00
|
|
|
[[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI arrival_token arrive(ptrdiff_t __update = 1) {
|
2024-01-20 23:38:02 -08:00
|
|
|
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update > 0, "barrier:arrive must be called with a value greater than 0");
|
2022-09-02 16:19:07 +02:00
|
|
|
return __b_.arrive(__update);
|
2020-02-18 09:58:34 -05:00
|
|
|
}
|
2020-02-24 10:09:29 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __phase) const {
|
2022-09-02 16:19:07 +02:00
|
|
|
__b_.wait(std::move(__phase));
|
2021-04-17 17:03:20 -04:00
|
|
|
}
|
2020-02-24 10:09:29 -05:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait() { wait(arrive()); }
|
2022-09-02 16:19:07 +02:00
|
|
|
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() { __b_.arrive_and_drop(); }
|
2020-02-18 09:58:34 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
|
2024-12-10 16:02:12 +01:00
|
|
|
# endif // _LIBCPP_STD_VER >= 20
|
2020-02-24 18:12:44 -05:00
|
|
|
|
2020-12-02 18:55:01 -05:00
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
|
2024-12-10 16:02:12 +01:00
|
|
|
# endif // _LIBCPP_HAS_THREADS
|
2024-07-15 09:11:23 -05:00
|
|
|
|
2024-12-10 16:02:12 +01:00
|
|
|
# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
|
|
|
|
# include <atomic>
|
|
|
|
# include <concepts>
|
|
|
|
# include <iterator>
|
|
|
|
# include <memory>
|
|
|
|
# include <stdexcept>
|
|
|
|
# include <variant>
|
|
|
|
# endif
|
2024-12-21 13:01:48 +01:00
|
|
|
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
|
2022-10-02 19:42:46 +02:00
|
|
|
|
2024-07-31 16:53:09 -05:00
|
|
|
#endif // _LIBCPP_BARRIER
|