1*4c3eb207Smrg// <stop_token> -*- C++ -*- 2*4c3eb207Smrg 3*4c3eb207Smrg// Copyright (C) 2019-2020 Free Software Foundation, Inc. 4*4c3eb207Smrg// 5*4c3eb207Smrg// This file is part of the GNU ISO C++ Library. This library is free 6*4c3eb207Smrg// software; you can redistribute it and/or modify it under the 7*4c3eb207Smrg// terms of the GNU General Public License as published by the 8*4c3eb207Smrg// Free Software Foundation; either version 3, or (at your option) 9*4c3eb207Smrg// any later version. 10*4c3eb207Smrg 11*4c3eb207Smrg// This library is distributed in the hope that it will be useful, 12*4c3eb207Smrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 13*4c3eb207Smrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*4c3eb207Smrg// GNU General Public License for more details. 15*4c3eb207Smrg 16*4c3eb207Smrg// Under Section 7 of GPL version 3, you are granted additional 17*4c3eb207Smrg// permissions described in the GCC Runtime Library Exception, version 18*4c3eb207Smrg// 3.1, as published by the Free Software Foundation. 19*4c3eb207Smrg 20*4c3eb207Smrg// You should have received a copy of the GNU General Public License and 21*4c3eb207Smrg// a copy of the GCC Runtime Library Exception along with this program; 22*4c3eb207Smrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23*4c3eb207Smrg// <http://www.gnu.org/licenses/>. 24*4c3eb207Smrg 25*4c3eb207Smrg/** @file include/stop_token 26*4c3eb207Smrg * This is a Standard C++ Library header. 27*4c3eb207Smrg */ 28*4c3eb207Smrg 29*4c3eb207Smrg#ifndef _GLIBCXX_STOP_TOKEN 30*4c3eb207Smrg#define _GLIBCXX_STOP_TOKEN 31*4c3eb207Smrg 32*4c3eb207Smrg#if __cplusplus > 201703L 33*4c3eb207Smrg 34*4c3eb207Smrg#include <atomic> 35*4c3eb207Smrg 36*4c3eb207Smrg#ifdef _GLIBCXX_HAS_GTHREADS 37*4c3eb207Smrg# define __cpp_lib_jthread 201911L 38*4c3eb207Smrg# include <bits/gthr.h> 39*4c3eb207Smrg# if __has_include(<semaphore>) 40*4c3eb207Smrg# include <semaphore> 41*4c3eb207Smrg# endif 42*4c3eb207Smrg#endif 43*4c3eb207Smrg 44*4c3eb207Smrgnamespace std _GLIBCXX_VISIBILITY(default) 45*4c3eb207Smrg{ 46*4c3eb207Smrg_GLIBCXX_BEGIN_NAMESPACE_VERSION 47*4c3eb207Smrg 48*4c3eb207Smrg /// Tag type indicating a stop_source should have no shared-stop-state. 49*4c3eb207Smrg struct nostopstate_t { explicit nostopstate_t() = default; }; 50*4c3eb207Smrg inline constexpr nostopstate_t nostopstate{}; 51*4c3eb207Smrg 52*4c3eb207Smrg class stop_source; 53*4c3eb207Smrg 54*4c3eb207Smrg /// Allow testing whether a stop request has been made on a `stop_source`. 55*4c3eb207Smrg class stop_token 56*4c3eb207Smrg { 57*4c3eb207Smrg public: 58*4c3eb207Smrg stop_token() noexcept = default; 59*4c3eb207Smrg 60*4c3eb207Smrg stop_token(const stop_token&) noexcept = default; 61*4c3eb207Smrg stop_token(stop_token&&) noexcept = default; 62*4c3eb207Smrg 63*4c3eb207Smrg ~stop_token() = default; 64*4c3eb207Smrg 65*4c3eb207Smrg stop_token& 66*4c3eb207Smrg operator=(const stop_token&) noexcept = default; 67*4c3eb207Smrg 68*4c3eb207Smrg stop_token& 69*4c3eb207Smrg operator=(stop_token&&) noexcept = default; 70*4c3eb207Smrg 71*4c3eb207Smrg [[nodiscard]] 72*4c3eb207Smrg bool 73*4c3eb207Smrg stop_possible() const noexcept 74*4c3eb207Smrg { 75*4c3eb207Smrg return static_cast<bool>(_M_state) && _M_state->_M_stop_possible(); 76*4c3eb207Smrg } 77*4c3eb207Smrg 78*4c3eb207Smrg [[nodiscard]] 79*4c3eb207Smrg bool 80*4c3eb207Smrg stop_requested() const noexcept 81*4c3eb207Smrg { 82*4c3eb207Smrg return static_cast<bool>(_M_state) && _M_state->_M_stop_requested(); 83*4c3eb207Smrg } 84*4c3eb207Smrg 85*4c3eb207Smrg void 86*4c3eb207Smrg swap(stop_token& __rhs) noexcept 87*4c3eb207Smrg { _M_state.swap(__rhs._M_state); } 88*4c3eb207Smrg 89*4c3eb207Smrg [[nodiscard]] 90*4c3eb207Smrg friend bool 91*4c3eb207Smrg operator==(const stop_token& __a, const stop_token& __b) 92*4c3eb207Smrg { return __a._M_state == __b._M_state; } 93*4c3eb207Smrg 94*4c3eb207Smrg friend void 95*4c3eb207Smrg swap(stop_token& __lhs, stop_token& __rhs) noexcept 96*4c3eb207Smrg { __lhs.swap(__rhs); } 97*4c3eb207Smrg 98*4c3eb207Smrg private: 99*4c3eb207Smrg friend class stop_source; 100*4c3eb207Smrg template<typename _Callback> 101*4c3eb207Smrg friend class stop_callback; 102*4c3eb207Smrg 103*4c3eb207Smrg static void 104*4c3eb207Smrg _S_yield() noexcept 105*4c3eb207Smrg { 106*4c3eb207Smrg#if defined __i386__ || defined __x86_64__ 107*4c3eb207Smrg __builtin_ia32_pause(); 108*4c3eb207Smrg#elif defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD 109*4c3eb207Smrg __gthread_yield(); 110*4c3eb207Smrg#endif 111*4c3eb207Smrg } 112*4c3eb207Smrg 113*4c3eb207Smrg#ifndef __cpp_lib_semaphore 114*4c3eb207Smrg // TODO: replace this with a real implementation of std::binary_semaphore 115*4c3eb207Smrg struct binary_semaphore 116*4c3eb207Smrg { 117*4c3eb207Smrg explicit binary_semaphore(int __d) : _M_counter(__d > 0) { } 118*4c3eb207Smrg 119*4c3eb207Smrg void release() { _M_counter.fetch_add(1, memory_order::release); } 120*4c3eb207Smrg 121*4c3eb207Smrg void acquire() 122*4c3eb207Smrg { 123*4c3eb207Smrg int __old = 1; 124*4c3eb207Smrg while (!_M_counter.compare_exchange_weak(__old, 0, 125*4c3eb207Smrg memory_order::acquire, 126*4c3eb207Smrg memory_order::relaxed)) 127*4c3eb207Smrg { 128*4c3eb207Smrg __old = 1; 129*4c3eb207Smrg _S_yield(); 130*4c3eb207Smrg } 131*4c3eb207Smrg } 132*4c3eb207Smrg 133*4c3eb207Smrg atomic<int> _M_counter; 134*4c3eb207Smrg }; 135*4c3eb207Smrg#endif 136*4c3eb207Smrg 137*4c3eb207Smrg struct _Stop_cb 138*4c3eb207Smrg { 139*4c3eb207Smrg using __cb_type = void(_Stop_cb*) noexcept; 140*4c3eb207Smrg __cb_type* _M_callback; 141*4c3eb207Smrg _Stop_cb* _M_prev = nullptr; 142*4c3eb207Smrg _Stop_cb* _M_next = nullptr; 143*4c3eb207Smrg bool* _M_destroyed = nullptr; 144*4c3eb207Smrg binary_semaphore _M_done{0}; 145*4c3eb207Smrg 146*4c3eb207Smrg [[__gnu__::__nonnull__]] 147*4c3eb207Smrg explicit 148*4c3eb207Smrg _Stop_cb(__cb_type* __cb) 149*4c3eb207Smrg : _M_callback(__cb) 150*4c3eb207Smrg { } 151*4c3eb207Smrg 152*4c3eb207Smrg void _M_run() noexcept { _M_callback(this); } 153*4c3eb207Smrg }; 154*4c3eb207Smrg 155*4c3eb207Smrg struct _Stop_state_t 156*4c3eb207Smrg { 157*4c3eb207Smrg using value_type = uint32_t; 158*4c3eb207Smrg static constexpr value_type _S_stop_requested_bit = 1; 159*4c3eb207Smrg static constexpr value_type _S_locked_bit = 2; 160*4c3eb207Smrg static constexpr value_type _S_ssrc_counter_inc = 4; 161*4c3eb207Smrg 162*4c3eb207Smrg std::atomic<value_type> _M_owners{1}; 163*4c3eb207Smrg std::atomic<value_type> _M_value{_S_ssrc_counter_inc}; 164*4c3eb207Smrg _Stop_cb* _M_head = nullptr; 165*4c3eb207Smrg#ifdef _GLIBCXX_HAS_GTHREADS 166*4c3eb207Smrg __gthread_t _M_requester; 167*4c3eb207Smrg#endif 168*4c3eb207Smrg 169*4c3eb207Smrg _Stop_state_t() noexcept { } 170*4c3eb207Smrg 171*4c3eb207Smrg bool 172*4c3eb207Smrg _M_stop_possible() noexcept 173*4c3eb207Smrg { 174*4c3eb207Smrg // true if a stop request has already been made or there are still 175*4c3eb207Smrg // stop_source objects that would allow one to be made. 176*4c3eb207Smrg return _M_value.load(memory_order::acquire) & ~_S_locked_bit; 177*4c3eb207Smrg } 178*4c3eb207Smrg 179*4c3eb207Smrg bool 180*4c3eb207Smrg _M_stop_requested() noexcept 181*4c3eb207Smrg { 182*4c3eb207Smrg return _M_value.load(memory_order::acquire) & _S_stop_requested_bit; 183*4c3eb207Smrg } 184*4c3eb207Smrg 185*4c3eb207Smrg void 186*4c3eb207Smrg _M_add_owner() noexcept 187*4c3eb207Smrg { 188*4c3eb207Smrg _M_owners.fetch_add(1, memory_order::relaxed); 189*4c3eb207Smrg } 190*4c3eb207Smrg 191*4c3eb207Smrg void 192*4c3eb207Smrg _M_release_ownership() noexcept 193*4c3eb207Smrg { 194*4c3eb207Smrg if (_M_owners.fetch_sub(1, memory_order::acq_rel) == 1) 195*4c3eb207Smrg delete this; 196*4c3eb207Smrg } 197*4c3eb207Smrg 198*4c3eb207Smrg void 199*4c3eb207Smrg _M_add_ssrc() noexcept 200*4c3eb207Smrg { 201*4c3eb207Smrg _M_value.fetch_add(_S_ssrc_counter_inc, memory_order::relaxed); 202*4c3eb207Smrg } 203*4c3eb207Smrg 204*4c3eb207Smrg void 205*4c3eb207Smrg _M_sub_ssrc() noexcept 206*4c3eb207Smrg { 207*4c3eb207Smrg _M_value.fetch_sub(_S_ssrc_counter_inc, memory_order::release); 208*4c3eb207Smrg } 209*4c3eb207Smrg 210*4c3eb207Smrg // Obtain lock. 211*4c3eb207Smrg void 212*4c3eb207Smrg _M_lock() noexcept 213*4c3eb207Smrg { 214*4c3eb207Smrg // Can use relaxed loads to get the current value. 215*4c3eb207Smrg // The successful call to _M_try_lock is an acquire operation. 216*4c3eb207Smrg auto __old = _M_value.load(memory_order::relaxed); 217*4c3eb207Smrg while (!_M_try_lock(__old, memory_order::relaxed)) 218*4c3eb207Smrg { } 219*4c3eb207Smrg } 220*4c3eb207Smrg 221*4c3eb207Smrg // Precondition: calling thread holds the lock. 222*4c3eb207Smrg void 223*4c3eb207Smrg _M_unlock() noexcept 224*4c3eb207Smrg { 225*4c3eb207Smrg _M_value.fetch_sub(_S_locked_bit, memory_order::release); 226*4c3eb207Smrg } 227*4c3eb207Smrg 228*4c3eb207Smrg bool 229*4c3eb207Smrg _M_request_stop() noexcept 230*4c3eb207Smrg { 231*4c3eb207Smrg // obtain lock and set stop_requested bit 232*4c3eb207Smrg auto __old = _M_value.load(memory_order::acquire); 233*4c3eb207Smrg do 234*4c3eb207Smrg { 235*4c3eb207Smrg if (__old & _S_stop_requested_bit) // stop request already made 236*4c3eb207Smrg return false; 237*4c3eb207Smrg } 238*4c3eb207Smrg while (!_M_try_lock_and_stop(__old)); 239*4c3eb207Smrg 240*4c3eb207Smrg#ifdef _GLIBCXX_HAS_GTHREADS 241*4c3eb207Smrg#ifdef _GLIBCXX_NATIVE_THREAD_ID 242*4c3eb207Smrg _M_requester = _GLIBCXX_NATIVE_THREAD_ID; 243*4c3eb207Smrg#else 244*4c3eb207Smrg _M_requester = __gthread_self(); 245*4c3eb207Smrg#endif 246*4c3eb207Smrg#endif 247*4c3eb207Smrg 248*4c3eb207Smrg while (_M_head) 249*4c3eb207Smrg { 250*4c3eb207Smrg bool __last_cb; 251*4c3eb207Smrg _Stop_cb* __cb = _M_head; 252*4c3eb207Smrg _M_head = _M_head->_M_next; 253*4c3eb207Smrg if (_M_head) 254*4c3eb207Smrg { 255*4c3eb207Smrg _M_head->_M_prev = nullptr; 256*4c3eb207Smrg __last_cb = false; 257*4c3eb207Smrg } 258*4c3eb207Smrg else 259*4c3eb207Smrg __last_cb = true; 260*4c3eb207Smrg 261*4c3eb207Smrg // Allow other callbacks to be unregistered while __cb runs. 262*4c3eb207Smrg _M_unlock(); 263*4c3eb207Smrg 264*4c3eb207Smrg bool __destroyed = false; 265*4c3eb207Smrg __cb->_M_destroyed = &__destroyed; 266*4c3eb207Smrg 267*4c3eb207Smrg // run callback 268*4c3eb207Smrg __cb->_M_run(); 269*4c3eb207Smrg 270*4c3eb207Smrg if (!__destroyed) 271*4c3eb207Smrg { 272*4c3eb207Smrg __cb->_M_destroyed = nullptr; 273*4c3eb207Smrg#ifdef _GLIBCXX_HAS_GTHREADS 274*4c3eb207Smrg // synchronize with destructor of stop_callback that owns *__cb 275*4c3eb207Smrg __cb->_M_done.release(); 276*4c3eb207Smrg#endif 277*4c3eb207Smrg } 278*4c3eb207Smrg 279*4c3eb207Smrg // Avoid relocking if we already know there are no more callbacks. 280*4c3eb207Smrg if (__last_cb) 281*4c3eb207Smrg return true; 282*4c3eb207Smrg 283*4c3eb207Smrg _M_lock(); 284*4c3eb207Smrg } 285*4c3eb207Smrg 286*4c3eb207Smrg _M_unlock(); 287*4c3eb207Smrg return true; 288*4c3eb207Smrg } 289*4c3eb207Smrg 290*4c3eb207Smrg [[__gnu__::__nonnull__]] 291*4c3eb207Smrg bool 292*4c3eb207Smrg _M_register_callback(_Stop_cb* __cb) noexcept 293*4c3eb207Smrg { 294*4c3eb207Smrg auto __old = _M_value.load(memory_order::acquire); 295*4c3eb207Smrg do 296*4c3eb207Smrg { 297*4c3eb207Smrg if (__old & _S_stop_requested_bit) // stop request already made 298*4c3eb207Smrg { 299*4c3eb207Smrg __cb->_M_run(); // run synchronously 300*4c3eb207Smrg return false; 301*4c3eb207Smrg } 302*4c3eb207Smrg 303*4c3eb207Smrg if (__old < _S_ssrc_counter_inc) // no stop_source owns *this 304*4c3eb207Smrg // No need to register callback if no stop request can be made. 305*4c3eb207Smrg // Returning false also means the stop_callback does not share 306*4c3eb207Smrg // ownership of this state, but that's not observable. 307*4c3eb207Smrg return false; 308*4c3eb207Smrg } 309*4c3eb207Smrg while (!_M_try_lock(__old)); 310*4c3eb207Smrg 311*4c3eb207Smrg __cb->_M_next = _M_head; 312*4c3eb207Smrg if (_M_head) 313*4c3eb207Smrg { 314*4c3eb207Smrg _M_head->_M_prev = __cb; 315*4c3eb207Smrg } 316*4c3eb207Smrg _M_head = __cb; 317*4c3eb207Smrg _M_unlock(); 318*4c3eb207Smrg return true; 319*4c3eb207Smrg } 320*4c3eb207Smrg 321*4c3eb207Smrg // Called by ~stop_callback just before destroying *__cb. 322*4c3eb207Smrg [[__gnu__::__nonnull__]] 323*4c3eb207Smrg void 324*4c3eb207Smrg _M_remove_callback(_Stop_cb* __cb) 325*4c3eb207Smrg { 326*4c3eb207Smrg _M_lock(); 327*4c3eb207Smrg 328*4c3eb207Smrg if (__cb == _M_head) 329*4c3eb207Smrg { 330*4c3eb207Smrg _M_head = _M_head->_M_next; 331*4c3eb207Smrg if (_M_head) 332*4c3eb207Smrg _M_head->_M_prev = nullptr; 333*4c3eb207Smrg _M_unlock(); 334*4c3eb207Smrg return; 335*4c3eb207Smrg } 336*4c3eb207Smrg else if (__cb->_M_prev) 337*4c3eb207Smrg { 338*4c3eb207Smrg __cb->_M_prev->_M_next = __cb->_M_next; 339*4c3eb207Smrg if (__cb->_M_next) 340*4c3eb207Smrg __cb->_M_next->_M_prev = __cb->_M_prev; 341*4c3eb207Smrg _M_unlock(); 342*4c3eb207Smrg return; 343*4c3eb207Smrg } 344*4c3eb207Smrg 345*4c3eb207Smrg _M_unlock(); 346*4c3eb207Smrg 347*4c3eb207Smrg // Callback is not in the list, so must have been removed by a call to 348*4c3eb207Smrg // _M_request_stop. 349*4c3eb207Smrg 350*4c3eb207Smrg#ifdef _GLIBCXX_HAS_GTHREADS 351*4c3eb207Smrg#ifdef _GLIBCXX_NATIVE_THREAD_ID 352*4c3eb207Smrg auto __tid = _GLIBCXX_NATIVE_THREAD_ID; 353*4c3eb207Smrg#else 354*4c3eb207Smrg auto __tid = __gthread_self(); 355*4c3eb207Smrg#endif 356*4c3eb207Smrg // Despite appearances there is no data race on _M_requester. The only 357*4c3eb207Smrg // write to it happens before the callback is removed from the list, 358*4c3eb207Smrg // and removing it from the list happens before this read. 359*4c3eb207Smrg if (!__gthread_equal(_M_requester, __tid)) 360*4c3eb207Smrg { 361*4c3eb207Smrg // Synchronize with completion of callback. 362*4c3eb207Smrg __cb->_M_done.acquire(); 363*4c3eb207Smrg // Safe for ~stop_callback to destroy *__cb now. 364*4c3eb207Smrg return; 365*4c3eb207Smrg } 366*4c3eb207Smrg#endif 367*4c3eb207Smrg if (__cb->_M_destroyed) 368*4c3eb207Smrg *__cb->_M_destroyed = true; 369*4c3eb207Smrg } 370*4c3eb207Smrg 371*4c3eb207Smrg // Try to obtain the lock. 372*4c3eb207Smrg // Returns true if the lock is acquired (with memory order acquire). 373*4c3eb207Smrg // Otherwise, sets __curval = _M_value.load(__failure) and returns false. 374*4c3eb207Smrg // Might fail spuriously, so must be called in a loop. 375*4c3eb207Smrg bool 376*4c3eb207Smrg _M_try_lock(value_type& __curval, 377*4c3eb207Smrg memory_order __failure = memory_order::acquire) noexcept 378*4c3eb207Smrg { 379*4c3eb207Smrg return _M_do_try_lock(__curval, 0, memory_order::acquire, __failure); 380*4c3eb207Smrg } 381*4c3eb207Smrg 382*4c3eb207Smrg // Try to obtain the lock to make a stop request. 383*4c3eb207Smrg // Returns true if the lock is acquired and the _S_stop_requested_bit is 384*4c3eb207Smrg // set (with memory order acq_rel so that other threads see the request). 385*4c3eb207Smrg // Otherwise, sets __curval = _M_value.load(memory_order::acquire) and 386*4c3eb207Smrg // returns false. 387*4c3eb207Smrg // Might fail spuriously, so must be called in a loop. 388*4c3eb207Smrg bool 389*4c3eb207Smrg _M_try_lock_and_stop(value_type& __curval) noexcept 390*4c3eb207Smrg { 391*4c3eb207Smrg return _M_do_try_lock(__curval, _S_stop_requested_bit, 392*4c3eb207Smrg memory_order::acq_rel, memory_order::acquire); 393*4c3eb207Smrg } 394*4c3eb207Smrg 395*4c3eb207Smrg bool 396*4c3eb207Smrg _M_do_try_lock(value_type& __curval, value_type __newbits, 397*4c3eb207Smrg memory_order __success, memory_order __failure) noexcept 398*4c3eb207Smrg { 399*4c3eb207Smrg if (__curval & _S_locked_bit) 400*4c3eb207Smrg { 401*4c3eb207Smrg _S_yield(); 402*4c3eb207Smrg __curval = _M_value.load(__failure); 403*4c3eb207Smrg return false; 404*4c3eb207Smrg } 405*4c3eb207Smrg __newbits |= _S_locked_bit; 406*4c3eb207Smrg return _M_value.compare_exchange_weak(__curval, __curval | __newbits, 407*4c3eb207Smrg __success, __failure); 408*4c3eb207Smrg } 409*4c3eb207Smrg }; 410*4c3eb207Smrg 411*4c3eb207Smrg struct _Stop_state_ref 412*4c3eb207Smrg { 413*4c3eb207Smrg _Stop_state_ref() = default; 414*4c3eb207Smrg 415*4c3eb207Smrg explicit 416*4c3eb207Smrg _Stop_state_ref(const stop_source&) 417*4c3eb207Smrg : _M_ptr(new _Stop_state_t()) 418*4c3eb207Smrg { } 419*4c3eb207Smrg 420*4c3eb207Smrg _Stop_state_ref(const _Stop_state_ref& __other) noexcept 421*4c3eb207Smrg : _M_ptr(__other._M_ptr) 422*4c3eb207Smrg { 423*4c3eb207Smrg if (_M_ptr) 424*4c3eb207Smrg _M_ptr->_M_add_owner(); 425*4c3eb207Smrg } 426*4c3eb207Smrg 427*4c3eb207Smrg _Stop_state_ref(_Stop_state_ref&& __other) noexcept 428*4c3eb207Smrg : _M_ptr(__other._M_ptr) 429*4c3eb207Smrg { 430*4c3eb207Smrg __other._M_ptr = nullptr; 431*4c3eb207Smrg } 432*4c3eb207Smrg 433*4c3eb207Smrg _Stop_state_ref& 434*4c3eb207Smrg operator=(const _Stop_state_ref& __other) noexcept 435*4c3eb207Smrg { 436*4c3eb207Smrg if (auto __ptr = __other._M_ptr; __ptr != _M_ptr) 437*4c3eb207Smrg { 438*4c3eb207Smrg if (__ptr) 439*4c3eb207Smrg __ptr->_M_add_owner(); 440*4c3eb207Smrg if (_M_ptr) 441*4c3eb207Smrg _M_ptr->_M_release_ownership(); 442*4c3eb207Smrg _M_ptr = __ptr; 443*4c3eb207Smrg } 444*4c3eb207Smrg return *this; 445*4c3eb207Smrg } 446*4c3eb207Smrg 447*4c3eb207Smrg _Stop_state_ref& 448*4c3eb207Smrg operator=(_Stop_state_ref&& __other) noexcept 449*4c3eb207Smrg { 450*4c3eb207Smrg _Stop_state_ref(std::move(__other)).swap(*this); 451*4c3eb207Smrg return *this; 452*4c3eb207Smrg } 453*4c3eb207Smrg 454*4c3eb207Smrg ~_Stop_state_ref() 455*4c3eb207Smrg { 456*4c3eb207Smrg if (_M_ptr) 457*4c3eb207Smrg _M_ptr->_M_release_ownership(); 458*4c3eb207Smrg } 459*4c3eb207Smrg 460*4c3eb207Smrg void 461*4c3eb207Smrg swap(_Stop_state_ref& __other) noexcept 462*4c3eb207Smrg { std::swap(_M_ptr, __other._M_ptr); } 463*4c3eb207Smrg 464*4c3eb207Smrg explicit operator bool() const noexcept { return _M_ptr != nullptr; } 465*4c3eb207Smrg 466*4c3eb207Smrg _Stop_state_t* operator->() const noexcept { return _M_ptr; } 467*4c3eb207Smrg 468*4c3eb207Smrg#if __cpp_impl_three_way_comparison >= 201907L 469*4c3eb207Smrg friend bool 470*4c3eb207Smrg operator==(const _Stop_state_ref&, const _Stop_state_ref&) = default; 471*4c3eb207Smrg#else 472*4c3eb207Smrg friend bool 473*4c3eb207Smrg operator==(const _Stop_state_ref& __lhs, const _Stop_state_ref& __rhs) 474*4c3eb207Smrg noexcept 475*4c3eb207Smrg { return __lhs._M_ptr == __rhs._M_ptr; } 476*4c3eb207Smrg 477*4c3eb207Smrg friend bool 478*4c3eb207Smrg operator!=(const _Stop_state_ref& __lhs, const _Stop_state_ref& __rhs) 479*4c3eb207Smrg noexcept 480*4c3eb207Smrg { return __lhs._M_ptr != __rhs._M_ptr; } 481*4c3eb207Smrg#endif 482*4c3eb207Smrg 483*4c3eb207Smrg private: 484*4c3eb207Smrg _Stop_state_t* _M_ptr = nullptr; 485*4c3eb207Smrg }; 486*4c3eb207Smrg 487*4c3eb207Smrg _Stop_state_ref _M_state; 488*4c3eb207Smrg 489*4c3eb207Smrg explicit 490*4c3eb207Smrg stop_token(const _Stop_state_ref& __state) noexcept 491*4c3eb207Smrg : _M_state{__state} 492*4c3eb207Smrg { } 493*4c3eb207Smrg }; 494*4c3eb207Smrg 495*4c3eb207Smrg /// A type that allows a stop request to be made. 496*4c3eb207Smrg class stop_source 497*4c3eb207Smrg { 498*4c3eb207Smrg public: 499*4c3eb207Smrg stop_source() : _M_state(*this) 500*4c3eb207Smrg { } 501*4c3eb207Smrg 502*4c3eb207Smrg explicit stop_source(std::nostopstate_t) noexcept 503*4c3eb207Smrg { } 504*4c3eb207Smrg 505*4c3eb207Smrg stop_source(const stop_source& __other) noexcept 506*4c3eb207Smrg : _M_state(__other._M_state) 507*4c3eb207Smrg { 508*4c3eb207Smrg if (_M_state) 509*4c3eb207Smrg _M_state->_M_add_ssrc(); 510*4c3eb207Smrg } 511*4c3eb207Smrg 512*4c3eb207Smrg stop_source(stop_source&&) noexcept = default; 513*4c3eb207Smrg 514*4c3eb207Smrg stop_source& 515*4c3eb207Smrg operator=(const stop_source& __other) noexcept 516*4c3eb207Smrg { 517*4c3eb207Smrg if (_M_state != __other._M_state) 518*4c3eb207Smrg { 519*4c3eb207Smrg stop_source __sink(std::move(*this)); 520*4c3eb207Smrg _M_state = __other._M_state; 521*4c3eb207Smrg if (_M_state) 522*4c3eb207Smrg _M_state->_M_add_ssrc(); 523*4c3eb207Smrg } 524*4c3eb207Smrg return *this; 525*4c3eb207Smrg } 526*4c3eb207Smrg 527*4c3eb207Smrg stop_source& 528*4c3eb207Smrg operator=(stop_source&&) noexcept = default; 529*4c3eb207Smrg 530*4c3eb207Smrg ~stop_source() 531*4c3eb207Smrg { 532*4c3eb207Smrg if (_M_state) 533*4c3eb207Smrg _M_state->_M_sub_ssrc(); 534*4c3eb207Smrg } 535*4c3eb207Smrg 536*4c3eb207Smrg [[nodiscard]] 537*4c3eb207Smrg bool 538*4c3eb207Smrg stop_possible() const noexcept 539*4c3eb207Smrg { 540*4c3eb207Smrg return static_cast<bool>(_M_state); 541*4c3eb207Smrg } 542*4c3eb207Smrg 543*4c3eb207Smrg [[nodiscard]] 544*4c3eb207Smrg bool 545*4c3eb207Smrg stop_requested() const noexcept 546*4c3eb207Smrg { 547*4c3eb207Smrg return static_cast<bool>(_M_state) && _M_state->_M_stop_requested(); 548*4c3eb207Smrg } 549*4c3eb207Smrg 550*4c3eb207Smrg bool 551*4c3eb207Smrg request_stop() const noexcept 552*4c3eb207Smrg { 553*4c3eb207Smrg if (stop_possible()) 554*4c3eb207Smrg return _M_state->_M_request_stop(); 555*4c3eb207Smrg return false; 556*4c3eb207Smrg } 557*4c3eb207Smrg 558*4c3eb207Smrg [[nodiscard]] 559*4c3eb207Smrg stop_token 560*4c3eb207Smrg get_token() const noexcept 561*4c3eb207Smrg { 562*4c3eb207Smrg return stop_token{_M_state}; 563*4c3eb207Smrg } 564*4c3eb207Smrg 565*4c3eb207Smrg void 566*4c3eb207Smrg swap(stop_source& __other) noexcept 567*4c3eb207Smrg { 568*4c3eb207Smrg _M_state.swap(__other._M_state); 569*4c3eb207Smrg } 570*4c3eb207Smrg 571*4c3eb207Smrg [[nodiscard]] 572*4c3eb207Smrg friend bool 573*4c3eb207Smrg operator==(const stop_source& __a, const stop_source& __b) noexcept 574*4c3eb207Smrg { 575*4c3eb207Smrg return __a._M_state == __b._M_state; 576*4c3eb207Smrg } 577*4c3eb207Smrg 578*4c3eb207Smrg friend void 579*4c3eb207Smrg swap(stop_source& __lhs, stop_source& __rhs) noexcept 580*4c3eb207Smrg { 581*4c3eb207Smrg __lhs.swap(__rhs); 582*4c3eb207Smrg } 583*4c3eb207Smrg 584*4c3eb207Smrg private: 585*4c3eb207Smrg stop_token::_Stop_state_ref _M_state; 586*4c3eb207Smrg }; 587*4c3eb207Smrg 588*4c3eb207Smrg /// A wrapper for callbacks to be run when a stop request is made. 589*4c3eb207Smrg template<typename _Callback> 590*4c3eb207Smrg class [[nodiscard]] stop_callback 591*4c3eb207Smrg { 592*4c3eb207Smrg static_assert(is_nothrow_destructible_v<_Callback>); 593*4c3eb207Smrg static_assert(is_invocable_v<_Callback>); 594*4c3eb207Smrg 595*4c3eb207Smrg public: 596*4c3eb207Smrg using callback_type = _Callback; 597*4c3eb207Smrg 598*4c3eb207Smrg template<typename _Cb, 599*4c3eb207Smrg enable_if_t<is_constructible_v<_Callback, _Cb>, int> = 0> 600*4c3eb207Smrg explicit 601*4c3eb207Smrg stop_callback(const stop_token& __token, _Cb&& __cb) 602*4c3eb207Smrg noexcept(is_nothrow_constructible_v<_Callback, _Cb>) 603*4c3eb207Smrg : _M_cb(std::forward<_Cb>(__cb)) 604*4c3eb207Smrg { 605*4c3eb207Smrg if (auto __state = __token._M_state) 606*4c3eb207Smrg { 607*4c3eb207Smrg if (__state->_M_register_callback(&_M_cb)) 608*4c3eb207Smrg _M_state.swap(__state); 609*4c3eb207Smrg } 610*4c3eb207Smrg } 611*4c3eb207Smrg 612*4c3eb207Smrg template<typename _Cb, 613*4c3eb207Smrg enable_if_t<is_constructible_v<_Callback, _Cb>, int> = 0> 614*4c3eb207Smrg explicit 615*4c3eb207Smrg stop_callback(stop_token&& __token, _Cb&& __cb) 616*4c3eb207Smrg noexcept(is_nothrow_constructible_v<_Callback, _Cb>) 617*4c3eb207Smrg : _M_cb(std::forward<_Cb>(__cb)) 618*4c3eb207Smrg { 619*4c3eb207Smrg if (auto& __state = __token._M_state) 620*4c3eb207Smrg { 621*4c3eb207Smrg if (__state->_M_register_callback(&_M_cb)) 622*4c3eb207Smrg _M_state.swap(__state); 623*4c3eb207Smrg } 624*4c3eb207Smrg } 625*4c3eb207Smrg 626*4c3eb207Smrg ~stop_callback() 627*4c3eb207Smrg { 628*4c3eb207Smrg if (_M_state) 629*4c3eb207Smrg { 630*4c3eb207Smrg _M_state->_M_remove_callback(&_M_cb); 631*4c3eb207Smrg } 632*4c3eb207Smrg } 633*4c3eb207Smrg 634*4c3eb207Smrg stop_callback(const stop_callback&) = delete; 635*4c3eb207Smrg stop_callback& operator=(const stop_callback&) = delete; 636*4c3eb207Smrg stop_callback(stop_callback&&) = delete; 637*4c3eb207Smrg stop_callback& operator=(stop_callback&&) = delete; 638*4c3eb207Smrg 639*4c3eb207Smrg private: 640*4c3eb207Smrg struct _Cb_impl : stop_token::_Stop_cb 641*4c3eb207Smrg { 642*4c3eb207Smrg template<typename _Cb> 643*4c3eb207Smrg explicit 644*4c3eb207Smrg _Cb_impl(_Cb&& __cb) 645*4c3eb207Smrg : _Stop_cb(&_S_execute), 646*4c3eb207Smrg _M_cb(std::forward<_Cb>(__cb)) 647*4c3eb207Smrg { } 648*4c3eb207Smrg 649*4c3eb207Smrg _Callback _M_cb; 650*4c3eb207Smrg 651*4c3eb207Smrg [[__gnu__::__nonnull__]] 652*4c3eb207Smrg static void 653*4c3eb207Smrg _S_execute(_Stop_cb* __that) noexcept 654*4c3eb207Smrg { 655*4c3eb207Smrg _Callback& __cb = static_cast<_Cb_impl*>(__that)->_M_cb; 656*4c3eb207Smrg std::forward<_Callback>(__cb)(); 657*4c3eb207Smrg } 658*4c3eb207Smrg }; 659*4c3eb207Smrg 660*4c3eb207Smrg _Cb_impl _M_cb; 661*4c3eb207Smrg stop_token::_Stop_state_ref _M_state; 662*4c3eb207Smrg }; 663*4c3eb207Smrg 664*4c3eb207Smrg template<typename _Callback> 665*4c3eb207Smrg stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; 666*4c3eb207Smrg 667*4c3eb207Smrg_GLIBCXX_END_NAMESPACE_VERSION 668*4c3eb207Smrg} // namespace 669*4c3eb207Smrg#endif // __cplusplus > 201703L 670*4c3eb207Smrg#endif // _GLIBCXX_STOP_TOKEN 671