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) != 0U) {
154 }
while (!try_lock_and_stop(old_value));
156 requester_thread_id = this_thread::id();
158 while (head !=
nullptr) {
159 bool last_callback =
false;
160 stop_callback_node* callback_node = head;
162 if (head !=
nullptr) {
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) != 0U) {
198 callback_node->run();
201 if (old_value < ssrc_counter_inc) {
206 callback_node->next = head;
207 if (head !=
nullptr) {
208 head->prev = callback_node;
210 head = callback_node;
221 void remove_callback(stop_callback_node* callback_node) {
224 if (callback_node == head) {
226 if (head !=
nullptr) {
227 head->prev =
nullptr;
232 if (callback_node->prev !=
nullptr) {
233 callback_node->prev->next = callback_node->next;
234 if (callback_node->next !=
nullptr) {
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 !=
nullptr) {
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) != 0U) {
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 :
313 if (ptr_ !=
nullptr) {
322 stop_state_reference(stop_state_reference&& other) noexcept :
324 other.ptr_ =
nullptr;
330 stop_state_reference&
operator=(
const stop_state_reference& other)
noexcept {
334 auto*
const new_ptr = other.ptr_;
335 if (new_ptr != ptr_) {
336 if (new_ptr !=
nullptr) {
337 new_ptr->add_owner();
339 if (ptr_ !=
nullptr) {
340 ptr_->release_ownership();
350 stop_state_reference&
operator=(stop_state_reference&& other)
noexcept {
354 stop_state_reference(
move(other)).swap(*
this);
361 ~stop_state_reference() {
362 if (ptr_ !=
nullptr) {
363 ptr_->release_ownership();
370 void swap(stop_state_reference& other)
noexcept { _NEFORCE
swap(ptr_, other.ptr_); }
375 explicit operator bool()
const noexcept {
return ptr_ !=
nullptr; }
380 stop_state* operator->()
const noexcept {
return ptr_; }
385 bool operator==(
const stop_state_reference& rhs)
const noexcept {
return ptr_ == rhs.ptr_; }
390 bool operator!=(
const stop_state_reference& rhs)
const noexcept {
return ptr_ != rhs.ptr_; }
394 stop_state_reference state_ref_;
396 friend class stop_source;
398 template <
typename Callback>
399 friend class stop_callback;
405 explicit stop_token(stop_state_reference state_ref) noexcept :
406 state_ref_{
move(state_ref)} {}
410 ~stop_token() = default;
411 stop_token(const stop_token&) noexcept = default;
412 stop_token& operator=(const stop_token&) noexcept = default;
413 stop_token(stop_token&&) noexcept = default;
414 stop_token& operator=(stop_token&&) noexcept = default;
421 return static_cast<bool>(state_ref_) && state_ref_->stop_possible();
429 return static_cast<bool>(state_ref_) && state_ref_->stop_requested();
436 void swap(stop_token& other)
noexcept { state_ref_.swap(other.state_ref_); }
445 NEFORCE_NODISCARD
bool operator==(
const stop_token& rhs)
const {
return state_ref_ == rhs.state_ref_; }