46 struct stop_callback_node {
47 using callback_type = void(stop_callback_node*)
48#ifdef NEFORCE_STANDARD_17
53 callback_type* callback;
54 stop_callback_node*
prev =
nullptr;
55 stop_callback_node*
next =
nullptr;
56 bool* destroyed =
nullptr;
63 explicit stop_callback_node(callback_type* cb) :
69 void run()
noexcept { callback(
this); }
80 static constexpr value_type stop_requested_bit = 1;
81 static constexpr value_type locked_bit = 2;
82 static constexpr value_type ssrc_counter_inc = 4;
86 stop_callback_node* head =
nullptr;
89 stop_state() =
default;
112 void release_ownership()
noexcept {
131 void lock()
noexcept {
148 bool request_stop()
noexcept {
151 if (old_value & stop_requested_bit) {
154 }
while (!try_lock_and_stop(old_value));
156 requester_thread_id = this_thread::id();
160 stop_callback_node* callback_node = head;
163 head->prev =
nullptr;
164 last_callback =
false;
166 last_callback =
true;
170 bool destroyed =
false;
171 callback_node->destroyed = &destroyed;
172 callback_node->run();
174 callback_node->destroyed =
nullptr;
175 callback_node->done_semaphore.
release();
194 bool register_callback(stop_callback_node* callback_node)
noexcept {
197 if (old_value & stop_requested_bit) {
198 callback_node->run();
201 if (old_value < ssrc_counter_inc) {
206 callback_node->next = head;
208 head->prev = callback_node;
210 head = callback_node;
221 void remove_callback(stop_callback_node* callback_node) {
224 if (callback_node == head) {
227 head->prev =
nullptr;
232 if (callback_node->prev) {
233 callback_node->prev->next = callback_node->next;
234 if (callback_node->next) {
235 callback_node->next->prev = callback_node->prev;
243 if (requester_thread_id != this_thread::id()) {
244 callback_node->done_semaphore.
acquire();
248 if (callback_node->destroyed) {
249 *callback_node->destroyed =
true;
268 bool try_lock_and_stop(value_type& current_value)
noexcept {
275 bool do_try_lock(value_type& current_value, value_type new_bits,
const memory_order success_order,
277 if (current_value & locked_bit) {
278 this_thread::relax();
279 current_value = value.
load(failure_order);
282 new_bits |= locked_bit;
283 return value.
compare_exchange_weak(current_value, current_value | new_bits, success_order, failure_order);
293 struct stop_state_reference {
295 stop_state* ptr_ =
nullptr;
298 stop_state_reference() =
default;
304 explicit stop_state_reference(
const stop_source&
ref) :
305 ptr_(
new stop_state()) {}
311 stop_state_reference(
const stop_state_reference& other) noexcept :
322 stop_state_reference(stop_state_reference&& other) noexcept :
324 other.ptr_ =
nullptr;
330 stop_state_reference&
operator=(
const stop_state_reference& other)
noexcept {
331 const auto new_ptr = other.ptr_;
332 if (new_ptr != ptr_) {
334 new_ptr->add_owner();
337 ptr_->release_ownership();
347 stop_state_reference&
operator=(stop_state_reference&& other)
noexcept {
348 stop_state_reference(
move(other)).swap(*
this);
355 ~stop_state_reference() {
357 ptr_->release_ownership();
364 void swap(stop_state_reference& other)
noexcept { _NEFORCE
swap(ptr_, other.ptr_); }
369 explicit operator bool()
const noexcept {
return ptr_ !=
nullptr; }
374 stop_state* operator->()
const noexcept {
return ptr_; }
379 bool operator==(
const stop_state_reference& rhs)
const noexcept {
return ptr_ == rhs.ptr_; }
384 bool operator!=(
const stop_state_reference& rhs)
const noexcept {
return ptr_ != rhs.ptr_; }
388 stop_state_reference state_ref_;
390 friend class stop_source;
392 template <
typename Callback>
393 friend class stop_callback;
399 explicit stop_token(stop_state_reference state_ref) noexcept :
400 state_ref_{
move(state_ref)} {}
404 ~stop_token() = default;
405 stop_token(const stop_token&) noexcept = default;
406 stop_token& operator=(const stop_token&) noexcept = default;
407 stop_token(stop_token&&) noexcept = default;
408 stop_token& operator=(stop_token&&) noexcept = default;
415 return static_cast<bool>(state_ref_) && state_ref_->stop_possible();
423 return static_cast<bool>(state_ref_) && state_ref_->stop_requested();
430 void swap(stop_token& other)
noexcept { state_ref_.swap(other.state_ref_); }
439 NEFORCE_NODISCARD
bool operator==(
const stop_token& rhs)
const {
return state_ref_ == rhs.state_ref_; }
580 struct callback_impl : stop_token::stop_callback_node {
581 template <
typename Cb>
582 explicit callback_impl(Cb&& callback) :
583 stop_callback_node(&execute_callback),
588 static void execute_callback(stop_callback_node* node)
noexcept {
589 Callback& cb =
static_cast<callback_impl*
>(node)->callback;
594 callback_impl callback_impl;
595 stop_token::stop_state_reference state_ref_;
604 template <
typename Cb, enable_if_t<is_constructible_v<Callback, Cb>,
int> = 0>
606 callback_impl(
forward<Cb>(callback)) {
607 if (
auto state_ref = token.state_ref_) {
608 if (state_ref->register_callback(&callback_impl)) {
609 state_ref_.swap(state_ref);
620 template <
typename Cb, enable_if_t<is_constructible_v<Callback, Cb>,
int> = 0>
622 callback_impl(
forward<Cb>(callback)) {
623 if (
auto& state_ref = token.state_ref_) {
624 if (state_ref->register_callback(&callback_impl)) {
625 state_ref_.swap(state_ref);
642 state_ref_->remove_callback(&callback_impl);