1// <stop_token> -*- C++ -*-
 
    3// Copyright (C) 2019-2021 Free Software Foundation, Inc.
 
    5// This file is part of the GNU ISO C++ Library.  This library is free
 
    6// software; you can redistribute it and/or modify it under the
 
    7// terms of the GNU General Public License as published by the
 
    8// Free Software Foundation; either version 3, or (at your option)
 
   11// This library is distributed in the hope that it will be useful,
 
   12// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
   13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
   14// GNU General Public License for more details.
 
   16// Under Section 7 of GPL version 3, you are granted additional
 
   17// permissions described in the GCC Runtime Library Exception, version
 
   18// 3.1, as published by the Free Software Foundation.
 
   20// You should have received a copy of the GNU General Public License and
 
   21// a copy of the GCC Runtime Library Exception along with this program;
 
   22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
   23// <http://www.gnu.org/licenses/>.
 
   25/** @file include/stop_token
 
   26 *  This is a Standard C++ Library header.
 
   29#ifndef _GLIBCXX_STOP_TOKEN
 
   30#define _GLIBCXX_STOP_TOKEN
 
   32#if __cplusplus > 201703L
 
   35#include <bits/std_thread.h>
 
   39#define __cpp_lib_jthread 201911L
 
   41namespace std _GLIBCXX_VISIBILITY(default)
 
   43_GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   45  /// Tag type indicating a stop_source should have no shared-stop-state.
 
   46  struct nostopstate_t { explicit nostopstate_t() = default; };
 
   47  inline constexpr nostopstate_t nostopstate{};
 
   51  /// Allow testing whether a stop request has been made on a `stop_source`.
 
   55    stop_token() noexcept = default;
 
   57    stop_token(const stop_token&) noexcept = default;
 
   58    stop_token(stop_token&&) noexcept = default;
 
   60    ~stop_token() = default;
 
   63    operator=(const stop_token&) noexcept = default;
 
   66    operator=(stop_token&&) noexcept = default;
 
   70    stop_possible() const noexcept
 
   72      return static_cast<bool>(_M_state) && _M_state->_M_stop_possible();
 
   77    stop_requested() const noexcept
 
   79      return static_cast<bool>(_M_state) && _M_state->_M_stop_requested();
 
   83    swap(stop_token& __rhs) noexcept
 
   84    { _M_state.swap(__rhs._M_state); }
 
   88    operator==(const stop_token& __a, const stop_token& __b)
 
   89    { return __a._M_state == __b._M_state; }
 
   92    swap(stop_token& __lhs, stop_token& __rhs) noexcept
 
   93    { __lhs.swap(__rhs); }
 
   96    friend class stop_source;
 
   97    template<typename _Callback>
 
   98      friend class stop_callback;
 
  103#if defined __i386__ || defined __x86_64__
 
  104      __builtin_ia32_pause();
 
  106      this_thread::yield();
 
  109#ifndef __cpp_lib_semaphore
 
  110    struct binary_semaphore
 
  112      explicit binary_semaphore(int __d) : _M_counter(__d > 0) { }
 
  114      void release() { _M_counter.fetch_add(1, memory_order::release); }
 
  119        while (!_M_counter.compare_exchange_weak(__old, 0,
 
  120                                                 memory_order::acquire,
 
  121                                                 memory_order::relaxed))
 
  128      atomic<int> _M_counter;
 
  134      using __cb_type = void(_Stop_cb*) noexcept;
 
  135      __cb_type* _M_callback;
 
  136      _Stop_cb* _M_prev = nullptr;
 
  137      _Stop_cb* _M_next = nullptr;
 
  138      bool* _M_destroyed = nullptr;
 
  139      binary_semaphore _M_done{0};
 
  141      [[__gnu__::__nonnull__]]
 
  143      _Stop_cb(__cb_type* __cb)
 
  147      void _M_run() noexcept { _M_callback(this); }
 
  152      using value_type = uint32_t;
 
  153      static constexpr value_type _S_stop_requested_bit = 1;
 
  154      static constexpr value_type _S_locked_bit = 2;
 
  155      static constexpr value_type _S_ssrc_counter_inc = 4;
 
  157      std::atomic<value_type> _M_owners{1};
 
  158      std::atomic<value_type> _M_value{_S_ssrc_counter_inc};
 
  159      _Stop_cb* _M_head = nullptr;
 
  160      std::thread::id _M_requester;
 
  162      _Stop_state_t() = default;
 
  165      _M_stop_possible() noexcept
 
  167        // true if a stop request has already been made or there are still
 
  168        // stop_source objects that would allow one to be made.
 
  169        return _M_value.load(memory_order::acquire) & ~_S_locked_bit;
 
  173      _M_stop_requested() noexcept
 
  175        return _M_value.load(memory_order::acquire) & _S_stop_requested_bit;
 
  179      _M_add_owner() noexcept
 
  181        _M_owners.fetch_add(1, memory_order::relaxed);
 
  185      _M_release_ownership() noexcept
 
  187        if (_M_owners.fetch_sub(1, memory_order::acq_rel) == 1)
 
  192      _M_add_ssrc() noexcept
 
  194        _M_value.fetch_add(_S_ssrc_counter_inc, memory_order::relaxed);
 
  198      _M_sub_ssrc() noexcept
 
  200        _M_value.fetch_sub(_S_ssrc_counter_inc, memory_order::release);
 
  207        // Can use relaxed loads to get the current value.
 
  208        // The successful call to _M_try_lock is an acquire operation.
 
  209        auto __old = _M_value.load(memory_order::relaxed);
 
  210        while (!_M_try_lock(__old, memory_order::relaxed))
 
  214      // Precondition: calling thread holds the lock.
 
  218        _M_value.fetch_sub(_S_locked_bit, memory_order::release);
 
  222      _M_request_stop() noexcept
 
  224        // obtain lock and set stop_requested bit
 
  225        auto __old = _M_value.load(memory_order::acquire);
 
  228            if (__old & _S_stop_requested_bit) // stop request already made
 
  231        while (!_M_try_lock_and_stop(__old));
 
  233        _M_requester = this_thread::get_id();
 
  238            _Stop_cb* __cb = _M_head;
 
  239            _M_head = _M_head->_M_next;
 
  242                _M_head->_M_prev = nullptr;
 
  248            // Allow other callbacks to be unregistered while __cb runs.
 
  251            bool __destroyed = false;
 
  252            __cb->_M_destroyed = &__destroyed;
 
  259                __cb->_M_destroyed = nullptr;
 
  261                // synchronize with destructor of stop_callback that owns *__cb
 
  262                if (!__gnu_cxx::__is_single_threaded())
 
  263                  __cb->_M_done.release();
 
  266            // Avoid relocking if we already know there are no more callbacks.
 
  277      [[__gnu__::__nonnull__]]
 
  279      _M_register_callback(_Stop_cb* __cb) noexcept
 
  281        auto __old = _M_value.load(memory_order::acquire);
 
  284            if (__old & _S_stop_requested_bit) // stop request already made
 
  286                __cb->_M_run(); // run synchronously
 
  290            if (__old < _S_ssrc_counter_inc) // no stop_source owns *this
 
  291              // No need to register callback if no stop request can be made.
 
  292              // Returning false also means the stop_callback does not share
 
  293              // ownership of this state, but that's not observable.
 
  296        while (!_M_try_lock(__old));
 
  298        __cb->_M_next = _M_head;
 
  301            _M_head->_M_prev = __cb;
 
  308      // Called by ~stop_callback just before destroying *__cb.
 
  309      [[__gnu__::__nonnull__]]
 
  311      _M_remove_callback(_Stop_cb* __cb)
 
  317            _M_head = _M_head->_M_next;
 
  319              _M_head->_M_prev = nullptr;
 
  323        else if (__cb->_M_prev)
 
  325            __cb->_M_prev->_M_next = __cb->_M_next;
 
  327              __cb->_M_next->_M_prev = __cb->_M_prev;
 
  334        // Callback is not in the list, so must have been removed by a call to
 
  337        // Despite appearances there is no data race on _M_requester. The only
 
  338        // write to it happens before the callback is removed from the list,
 
  339        // and removing it from the list happens before this read.
 
  340        if (!(_M_requester == this_thread::get_id()))
 
  342            // Synchronize with completion of callback.
 
  343            __cb->_M_done.acquire();
 
  344            // Safe for ~stop_callback to destroy *__cb now.
 
  348        if (__cb->_M_destroyed)
 
  349          *__cb->_M_destroyed = true;
 
  352      // Try to obtain the lock.
 
  353      // Returns true if the lock is acquired (with memory order acquire).
 
  354      // Otherwise, sets __curval = _M_value.load(__failure) and returns false.
 
  355      // Might fail spuriously, so must be called in a loop.
 
  357      _M_try_lock(value_type& __curval,
 
  358                  memory_order __failure = memory_order::acquire) noexcept
 
  360        return _M_do_try_lock(__curval, 0, memory_order::acquire, __failure);
 
  363      // Try to obtain the lock to make a stop request.
 
  364      // Returns true if the lock is acquired and the _S_stop_requested_bit is
 
  365      // set (with memory order acq_rel so that other threads see the request).
 
  366      // Otherwise, sets __curval = _M_value.load(memory_order::acquire) and
 
  368      // Might fail spuriously, so must be called in a loop.
 
  370      _M_try_lock_and_stop(value_type& __curval) noexcept
 
  372        return _M_do_try_lock(__curval, _S_stop_requested_bit,
 
  373                              memory_order::acq_rel, memory_order::acquire);
 
  377      _M_do_try_lock(value_type& __curval, value_type __newbits,
 
  378                     memory_order __success, memory_order __failure) noexcept
 
  380        if (__curval & _S_locked_bit)
 
  383            __curval = _M_value.load(__failure);
 
  386        __newbits |= _S_locked_bit;
 
  387        return _M_value.compare_exchange_weak(__curval, __curval | __newbits,
 
  388                                              __success, __failure);
 
  392    struct _Stop_state_ref
 
  394      _Stop_state_ref() = default;
 
  397      _Stop_state_ref(const stop_source&)
 
  398      : _M_ptr(new _Stop_state_t())
 
  401      _Stop_state_ref(const _Stop_state_ref& __other) noexcept
 
  402      : _M_ptr(__other._M_ptr)
 
  405          _M_ptr->_M_add_owner();
 
  408      _Stop_state_ref(_Stop_state_ref&& __other) noexcept
 
  409      : _M_ptr(__other._M_ptr)
 
  411        __other._M_ptr = nullptr;
 
  415      operator=(const _Stop_state_ref& __other) noexcept
 
  417        if (auto __ptr = __other._M_ptr; __ptr != _M_ptr)
 
  420              __ptr->_M_add_owner();
 
  422              _M_ptr->_M_release_ownership();
 
  429      operator=(_Stop_state_ref&& __other) noexcept
 
  431        _Stop_state_ref(std::move(__other)).swap(*this);
 
  438          _M_ptr->_M_release_ownership();
 
  442      swap(_Stop_state_ref& __other) noexcept
 
  443      { std::swap(_M_ptr, __other._M_ptr); }
 
  445      explicit operator bool() const noexcept { return _M_ptr != nullptr; }
 
  447      _Stop_state_t* operator->() const noexcept { return _M_ptr; }
 
  449#if __cpp_impl_three_way_comparison >= 201907L
 
  451      operator==(const _Stop_state_ref&, const _Stop_state_ref&) = default;
 
  454      operator==(const _Stop_state_ref& __lhs, const _Stop_state_ref& __rhs)
 
  456      { return __lhs._M_ptr == __rhs._M_ptr; }
 
  459      operator!=(const _Stop_state_ref& __lhs, const _Stop_state_ref& __rhs)
 
  461      { return __lhs._M_ptr != __rhs._M_ptr; }
 
  465      _Stop_state_t* _M_ptr = nullptr;
 
  468    _Stop_state_ref _M_state;
 
  471    stop_token(const _Stop_state_ref& __state) noexcept
 
  476  /// A type that allows a stop request to be made.
 
  480    stop_source() : _M_state(*this)
 
  483    explicit stop_source(std::nostopstate_t) noexcept
 
  486    stop_source(const stop_source& __other) noexcept
 
  487    : _M_state(__other._M_state)
 
  490        _M_state->_M_add_ssrc();
 
  493    stop_source(stop_source&&) noexcept = default;
 
  496    operator=(const stop_source& __other) noexcept
 
  498      if (_M_state != __other._M_state)
 
  500          stop_source __sink(std::move(*this));
 
  501          _M_state = __other._M_state;
 
  503            _M_state->_M_add_ssrc();
 
  509    operator=(stop_source&&) noexcept = default;
 
  514        _M_state->_M_sub_ssrc();
 
  519    stop_possible() const noexcept
 
  521      return static_cast<bool>(_M_state);
 
  526    stop_requested() const noexcept
 
  528      return static_cast<bool>(_M_state) && _M_state->_M_stop_requested();
 
  532    request_stop() const noexcept
 
  535        return _M_state->_M_request_stop();
 
  541    get_token() const noexcept
 
  543      return stop_token{_M_state};
 
  547    swap(stop_source& __other) noexcept
 
  549      _M_state.swap(__other._M_state);
 
  554    operator==(const stop_source& __a, const stop_source& __b) noexcept
 
  556      return __a._M_state == __b._M_state;
 
  560    swap(stop_source& __lhs, stop_source& __rhs) noexcept
 
  566    stop_token::_Stop_state_ref _M_state;
 
  569  /// A wrapper for callbacks to be run when a stop request is made.
 
  570  template<typename _Callback>
 
  571    class [[nodiscard]] stop_callback
 
  573      static_assert(is_nothrow_destructible_v<_Callback>);
 
  574      static_assert(is_invocable_v<_Callback>);
 
  577      using callback_type = _Callback;
 
  579      template<typename _Cb,
 
  580               enable_if_t<is_constructible_v<_Callback, _Cb>, int> = 0>
 
  582        stop_callback(const stop_token& __token, _Cb&& __cb)
 
  583        noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
 
  584        : _M_cb(std::forward<_Cb>(__cb))
 
  586          if (auto __state = __token._M_state)
 
  588              if (__state->_M_register_callback(&_M_cb))
 
  589                _M_state.swap(__state);
 
  593      template<typename _Cb,
 
  594               enable_if_t<is_constructible_v<_Callback, _Cb>, int> = 0>
 
  596        stop_callback(stop_token&& __token, _Cb&& __cb)
 
  597        noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
 
  598        : _M_cb(std::forward<_Cb>(__cb))
 
  600          if (auto& __state = __token._M_state)
 
  602              if (__state->_M_register_callback(&_M_cb))
 
  603                _M_state.swap(__state);
 
  611            _M_state->_M_remove_callback(&_M_cb);
 
  615      stop_callback(const stop_callback&) = delete;
 
  616      stop_callback& operator=(const stop_callback&) = delete;
 
  617      stop_callback(stop_callback&&) = delete;
 
  618      stop_callback& operator=(stop_callback&&) = delete;
 
  621      struct _Cb_impl : stop_token::_Stop_cb
 
  623        template<typename _Cb>
 
  626          : _Stop_cb(&_S_execute),
 
  627            _M_cb(std::forward<_Cb>(__cb))
 
  632        [[__gnu__::__nonnull__]]
 
  634        _S_execute(_Stop_cb* __that) noexcept
 
  636          _Callback& __cb = static_cast<_Cb_impl*>(__that)->_M_cb;
 
  637          std::forward<_Callback>(__cb)();
 
  642      stop_token::_Stop_state_ref _M_state;
 
  645  template<typename _Callback>
 
  646    stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
 
  648_GLIBCXX_END_NAMESPACE_VERSION
 
  650#endif // __cplusplus > 201703L
 
  651#endif // _GLIBCXX_STOP_TOKEN