40 struct stop_callback_node {
41 using callback_type = void(stop_callback_node*)
42#ifdef MSTL_STANDARD_17__
47 callback_type* callback;
48 stop_callback_node*
prev =
nullptr;
49 stop_callback_node*
next =
nullptr;
50 bool* destroyed =
nullptr;
57 explicit stop_callback_node(callback_type* cb)
76 static constexpr value_type stop_requested_bit = 1;
77 static constexpr value_type locked_bit = 2;
78 static constexpr value_type ssrc_counter_inc = 4;
82 stop_callback_node* head =
nullptr;
85 stop_state() =
default;
106 void add_owner()
noexcept {
114 void release_ownership()
noexcept {
122 void add_stop_source()
noexcept {
129 void remove_stop_source()
noexcept {
136 void lock()
noexcept {
144 void unlock()
noexcept {
154 bool request_stop()
noexcept {
157 if (old_value & stop_requested_bit) {
160 }
while (!try_lock_and_stop(old_value));
162 requester_thread_id = this_thread::id();
166 stop_callback_node* callback_node = head;
169 head->prev =
nullptr;
170 last_callback =
false;
172 last_callback =
true;
176 bool destroyed =
false;
177 callback_node->destroyed = &destroyed;
178 callback_node->run();
180 callback_node->destroyed =
nullptr;
181 callback_node->done_semaphore.
release();
184 if (last_callback)
return true;
198 bool register_callback(stop_callback_node* callback_node)
noexcept {
201 if (old_value & stop_requested_bit) {
202 callback_node->run();
205 if (old_value < ssrc_counter_inc) {
210 callback_node->next = head;
212 head->prev = callback_node;
214 head = callback_node;
225 void remove_callback(stop_callback_node* callback_node) {
228 if (callback_node == head) {
231 head->prev =
nullptr;
235 if (callback_node->prev) {
236 callback_node->prev->next = callback_node->next;
237 if (callback_node->next)
238 callback_node->next->prev = callback_node->prev;
245 if (requester_thread_id != this_thread::id()) {
246 callback_node->done_semaphore.
acquire();
250 if (callback_node->destroyed) {
251 *callback_node->destroyed =
true;
261 bool try_lock(value_type& current_value,
271 bool try_lock_and_stop(value_type& current_value)
noexcept {
273 current_value, stop_requested_bit,
280 bool do_try_lock(value_type& current_value, value_type new_bits,
282 if (current_value & locked_bit) {
283 this_thread::relax();
284 current_value = value.
load(failure_order);
287 new_bits |= locked_bit;
289 current_value, current_value | new_bits,
290 success_order, failure_order);
300 struct stop_state_reference {
302 stop_state* ptr_ =
nullptr;
305 stop_state_reference() =
default;
311 explicit stop_state_reference(
const stop_source&
ref)
312 : ptr_(
new stop_state()) {}
318 stop_state_reference(
const stop_state_reference& other) noexcept
329 stop_state_reference(stop_state_reference&& other) noexcept
331 other.ptr_ =
nullptr;
337 stop_state_reference& operator =(
const stop_state_reference& other)
noexcept {
338 const auto new_ptr = other.ptr_;
339 if (new_ptr != ptr_) {
341 new_ptr->add_owner();
344 ptr_->release_ownership();
354 stop_state_reference& operator =(stop_state_reference&& other)
noexcept {
355 stop_state_reference(
move(other)).swap(*
this);
362 ~stop_state_reference() {
364 ptr_->release_ownership();
371 void swap(stop_state_reference& other)
noexcept {
378 explicit operator bool()
const noexcept {
379 return ptr_ !=
nullptr;
385 stop_state* operator ->()
const noexcept {
392 bool operator ==(
const stop_state_reference& rhs)
const noexcept {
393 return ptr_ == rhs.ptr_;
399 bool operator !=(
const stop_state_reference& rhs)
const noexcept {
400 return ptr_ != rhs.ptr_;
405 stop_state_reference state_ref_;
407 friend class stop_source;
409 template <
typename Callback>
410 friend class stop_callback;
416 explicit stop_token(stop_state_reference state_ref) noexcept
417 : state_ref_{
move(state_ref)} {}
421 ~stop_token() = default;
422 stop_token(const stop_token&) noexcept = default;
423 stop_token& operator =(const stop_token&) noexcept = default;
424 stop_token(stop_token&&) noexcept = default;
425 stop_token& operator =(stop_token&&) noexcept = default;
432 return static_cast<bool>(state_ref_) && state_ref_->stop_possible();
440 return static_cast<bool>(state_ref_) && state_ref_->stop_requested();
447 void swap(stop_token& other)
noexcept {
448 state_ref_.swap(other.state_ref_);
459 return state_ref_ == rhs.state_ref_;
605 static_assert(is_nothrow_destructible_v<Callback>,
"Callback should be nothrow destructible.");
606 static_assert(is_invocable_v<Callback>,
"Callback should be invocable.");
612 struct callback_impl : stop_token::stop_callback_node {
613 template <
typename Cb>
614 explicit callback_impl(Cb&& callback)
615 : stop_callback_node(&execute_callback),
620 static void execute_callback(stop_callback_node* node)
noexcept {
621 Callback& cb =
static_cast<callback_impl*
>(node)->callback;
626 callback_impl callback_impl;
627 stop_token::stop_state_reference state_ref_;
636 template <
typename Cb, enable_if_t<is_constructible_v<Callback, Cb>,
int> = 0>
638 noexcept(is_nothrow_constructible_v<Callback, Cb>)
639 : callback_impl(
forward<Cb>(callback)) {
640 if (
auto state_ref = token.state_ref_) {
641 if (state_ref->register_callback(&callback_impl)) {
642 state_ref_.swap(state_ref);
653 template <
typename Cb, enable_if_t<is_constructible_v<Callback, Cb>,
int> = 0>
655 noexcept(is_nothrow_constructible_v<Callback, Cb>)
656 : callback_impl(
forward<Cb>(callback)) {
657 if (
auto& state_ref = token.state_ref_) {
658 if (state_ref->register_callback(&callback_impl)) {
659 state_ref_.swap(state_ref);
676 state_ref_->remove_callback(&callback_impl);