File indexing completed on 2026-05-03 08:14:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef _LIBCPP___STOP_TOKEN_STOP_STATE_H
0011 #define _LIBCPP___STOP_TOKEN_STOP_STATE_H
0012
0013 #include <__assert>
0014 #include <__config>
0015 #include <__stop_token/atomic_unique_lock.h>
0016 #include <__stop_token/intrusive_list_view.h>
0017 #include <__thread/id.h>
0018 #include <atomic>
0019 #include <cstdint>
0020
0021 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0022 # pragma GCC system_header
0023 #endif
0024
0025 _LIBCPP_BEGIN_NAMESPACE_STD
0026
0027 #if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_THREADS
0028
0029 struct __stop_callback_base : __intrusive_node_base<__stop_callback_base> {
0030 using __callback_fn_t _LIBCPP_NODEBUG = void(__stop_callback_base*) noexcept;
0031 _LIBCPP_HIDE_FROM_ABI explicit __stop_callback_base(__callback_fn_t* __callback_fn) : __callback_fn_(__callback_fn) {}
0032
0033 _LIBCPP_HIDE_FROM_ABI void __invoke() noexcept { __callback_fn_(this); }
0034
0035 __callback_fn_t* __callback_fn_;
0036 atomic<bool> __completed_ = false;
0037 bool* __destroyed_ = nullptr;
0038 };
0039
0040 class __stop_state {
0041 static constexpr uint32_t __stop_requested_bit = 1;
0042 static constexpr uint32_t __callback_list_locked_bit = 1 << 1;
0043 static constexpr uint32_t __stop_source_counter_shift = 2;
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 atomic<uint32_t> __state_ = 0;
0055
0056
0057
0058
0059 atomic<uint32_t> __ref_count_ = 0;
0060
0061 using __state_t _LIBCPP_NODEBUG = uint32_t;
0062 using __callback_list_lock _LIBCPP_NODEBUG = __atomic_unique_lock<__state_t, __callback_list_locked_bit>;
0063 using __callback_list _LIBCPP_NODEBUG = __intrusive_list_view<__stop_callback_base>;
0064
0065 __callback_list __callback_list_;
0066 __thread_id __requesting_thread_;
0067
0068 public:
0069 _LIBCPP_HIDE_FROM_ABI __stop_state() noexcept = default;
0070
0071 _LIBCPP_HIDE_FROM_ABI void __increment_stop_source_counter() noexcept {
0072 _LIBCPP_ASSERT_UNCATEGORIZED(
0073 __state_.load(std::memory_order_relaxed) <= static_cast<__state_t>(~(1 << __stop_source_counter_shift)),
0074 "stop_source's counter reaches the maximum. Incrementing the counter will overflow");
0075 __state_.fetch_add(1 << __stop_source_counter_shift, std::memory_order_relaxed);
0076 }
0077
0078
0079
0080 _LIBCPP_HIDE_FROM_ABI void __decrement_stop_source_counter() noexcept {
0081 _LIBCPP_ASSERT_UNCATEGORIZED(
0082 __state_.load(std::memory_order_relaxed) >= static_cast<__state_t>(1 << __stop_source_counter_shift),
0083 "stop_source's counter is 0. Decrementing the counter will underflow");
0084 __state_.fetch_sub(1 << __stop_source_counter_shift, std::memory_order_relaxed);
0085 }
0086
0087 _LIBCPP_HIDE_FROM_ABI bool __stop_requested() const noexcept {
0088
0089
0090
0091
0092 return (__state_.load(std::memory_order_acquire) & __stop_requested_bit) != 0;
0093 }
0094
0095 _LIBCPP_HIDE_FROM_ABI bool __stop_possible_for_stop_token() const noexcept {
0096
0097
0098
0099 __state_t __curent_state = __state_.load(std::memory_order_acquire);
0100 return ((__curent_state & __stop_requested_bit) != 0) || ((__curent_state >> __stop_source_counter_shift) != 0);
0101 }
0102
0103 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __request_stop() noexcept {
0104 auto __cb_list_lock = __try_lock_for_request_stop();
0105 if (!__cb_list_lock.__owns_lock()) {
0106 return false;
0107 }
0108 __requesting_thread_ = this_thread::get_id();
0109
0110 while (!__callback_list_.__empty()) {
0111 auto __cb = __callback_list_.__pop_front();
0112
0113
0114 __cb_list_lock.__unlock();
0115
0116 bool __destroyed = false;
0117 __cb->__destroyed_ = &__destroyed;
0118
0119 __cb->__invoke();
0120
0121
0122 if (!__destroyed) {
0123
0124
0125 __cb->__destroyed_ = nullptr;
0126
0127
0128
0129
0130 __cb->__completed_.store(true, std::memory_order_release);
0131 __cb->__completed_.notify_all();
0132 }
0133
0134 __cb_list_lock.__lock();
0135 }
0136
0137 return true;
0138 }
0139
0140 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __add_callback(__stop_callback_base* __cb) noexcept {
0141
0142 const auto __give_up_trying_to_lock_condition = [__cb](__state_t __state) {
0143 if ((__state & __stop_requested_bit) != 0) {
0144
0145 __cb->__invoke();
0146 return true;
0147 }
0148
0149 return (__state >> __stop_source_counter_shift) == 0;
0150 };
0151
0152 __callback_list_lock __cb_list_lock(__state_, __give_up_trying_to_lock_condition);
0153
0154 if (!__cb_list_lock.__owns_lock()) {
0155 return false;
0156 }
0157
0158 __callback_list_.__push_front(__cb);
0159
0160 return true;
0161
0162
0163
0164 }
0165
0166
0167 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __remove_callback(__stop_callback_base* __cb) noexcept {
0168 __callback_list_lock __cb_list_lock(__state_);
0169
0170
0171 bool __potentially_executing_now = __cb->__prev_ == nullptr && !__callback_list_.__is_head(__cb);
0172
0173 if (__potentially_executing_now) {
0174 auto __requested_thread = __requesting_thread_;
0175 __cb_list_lock.__unlock();
0176
0177 if (std::this_thread::get_id() != __requested_thread) {
0178
0179
0180 __cb->__completed_.wait(false, std::memory_order_acquire);
0181 } else {
0182
0183
0184
0185 if (__cb->__destroyed_) {
0186 *__cb->__destroyed_ = true;
0187 }
0188 }
0189 } else {
0190 __callback_list_.__remove(__cb);
0191 }
0192 }
0193
0194 private:
0195 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI __callback_list_lock __try_lock_for_request_stop() noexcept {
0196
0197 const auto __lock_fail_condition = [](__state_t __state) { return (__state & __stop_requested_bit) != 0; };
0198
0199
0200 const auto __after_lock_state = [](__state_t __state) {
0201 return __state | __callback_list_locked_bit | __stop_requested_bit;
0202 };
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 const auto __locked_ordering = std::memory_order_acq_rel;
0214
0215 return __callback_list_lock(__state_, __lock_fail_condition, __after_lock_state, __locked_ordering);
0216 }
0217
0218 template <class _Tp>
0219 friend struct __intrusive_shared_ptr_traits;
0220 };
0221
0222 template <class _Tp>
0223 struct __intrusive_shared_ptr_traits;
0224
0225 template <>
0226 struct __intrusive_shared_ptr_traits<__stop_state> {
0227 _LIBCPP_HIDE_FROM_ABI static atomic<uint32_t>& __get_atomic_ref_count(__stop_state& __state) {
0228 return __state.__ref_count_;
0229 }
0230 };
0231
0232 #endif
0233
0234 _LIBCPP_END_NAMESPACE_STD
0235
0236 #endif