1 // <stop_token> -*- C++ -*-
3 // Copyright (C) 2019-2020 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_mutex.h>
36 #include <ext/concurrence.h>
37 #include <bits/unique_ptr.h>
38 #include <bits/shared_ptr.h>
40 #ifdef _GLIBCXX_HAS_GTHREADS
41 # define __cpp_lib_jthread 201907L
44 namespace std _GLIBCXX_VISIBILITY(default)
46 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 /// Tag type indicating a stop_source should have no shared-stop-state.
49 struct nostopstate_t { explicit nostopstate_t() = default; };
50 inline constexpr nostopstate_t nostopstate{};
52 /// Allow testing whether a stop request has been made on a `stop_source`.
56 stop_token() noexcept = default;
58 stop_token(const stop_token& __other) noexcept = default;
59 stop_token(stop_token&& __other) noexcept = default;
61 ~stop_token() = default;
64 operator=(const stop_token& __rhs) noexcept = default;
67 operator=(stop_token&& __rhs) noexcept = default;
71 stop_possible() const noexcept
73 return static_cast<bool>(_M_state);
78 stop_requested() const noexcept
80 return stop_possible() && _M_state->_M_stop_requested();
84 swap(stop_token& __rhs) noexcept
85 { _M_state.swap(__rhs._M_state); }
89 operator==(const stop_token& __a, const stop_token& __b)
90 { return __a._M_state == __b._M_state; }
93 swap(stop_token& __lhs, stop_token& __rhs) noexcept
94 { __lhs.swap(__rhs); }
97 friend class stop_source;
98 template<typename _Callback>
99 friend class stop_callback;
103 void(*_M_callback)(_Stop_cb*);
104 _Stop_cb* _M_prev = nullptr;
105 _Stop_cb* _M_next = nullptr;
107 template<typename _Cb>
109 : _M_callback(std::forward<_Cb>(__cb))
113 _M_linked() const noexcept
115 return (_M_prev != nullptr)
116 || (_M_next != nullptr);
120 _S_execute(_Stop_cb* __cb) noexcept
122 __cb->_M_callback(__cb);
123 __cb->_M_prev = __cb->_M_next = nullptr;
129 std::atomic<bool> _M_stopped{false};
130 _Stop_cb* _M_head = nullptr;
131 #ifdef _GLIBCXX_HAS_GTHREADS
135 _Stop_state_t() = default;
138 _M_stop_requested() noexcept
146 bool __stopped = false;
147 if (_M_stopped.compare_exchange_strong(__stopped, true))
149 #ifdef _GLIBCXX_HAS_GTHREADS
150 std::lock_guard<std::mutex> __lck{_M_mtx};
155 _M_head = _M_head->_M_next;
156 _Stop_cb::_S_execute(__p);
164 _M_register_callback(_Stop_cb* __cb)
166 #ifdef _GLIBCXX_HAS_GTHREADS
167 std::lock_guard<std::mutex> __lck{_M_mtx};
172 __cb->_M_next = _M_head;
175 _M_head->_M_prev = __cb;
182 _M_remove_callback(_Stop_cb* __cb)
184 #ifdef _GLIBCXX_HAS_GTHREADS
185 std::lock_guard<std::mutex> __lck{_M_mtx};
189 _M_head = _M_head->_M_next;
192 _M_head->_M_prev = nullptr;
195 else if (!__cb->_M_linked())
201 __cb->_M_prev->_M_next = __cb->_M_next;
204 __cb->_M_next->_M_prev = __cb->_M_prev;
210 using _Stop_state = std::shared_ptr<_Stop_state_t>;
211 _Stop_state _M_state;
214 stop_token(const _Stop_state& __state) noexcept
219 /// A type that allows a stop request to be made.
224 : _M_state(std::make_shared<stop_token::_Stop_state_t>())
227 explicit stop_source(std::nostopstate_t) noexcept
230 stop_source(const stop_source& __other) noexcept
231 : _M_state(__other._M_state)
234 stop_source(stop_source&& __other) noexcept
235 : _M_state(std::move(__other._M_state))
239 operator=(const stop_source& __rhs) noexcept
241 if (_M_state != __rhs._M_state)
242 _M_state = __rhs._M_state;
247 operator=(stop_source&& __rhs) noexcept
249 std::swap(_M_state, __rhs._M_state);
255 stop_possible() const noexcept
257 return static_cast<bool>(_M_state);
262 stop_requested() const noexcept
264 return stop_possible() && _M_state->_M_stop_requested();
268 request_stop() const noexcept
271 return _M_state->_M_request_stop();
277 get_token() const noexcept
279 return stop_token{_M_state};
283 swap(stop_source& __other) noexcept
285 _M_state.swap(__other._M_state);
290 operator==(const stop_source& __a, const stop_source& __b) noexcept
292 return __a._M_state == __b._M_state;
296 swap(stop_source& __lhs, stop_source& __rhs) noexcept
302 stop_token::_Stop_state _M_state;
305 /// A wrapper for callbacks to be run when a stop request is made.
306 template<typename _Callback>
307 class [[nodiscard]] stop_callback
308 : private stop_token::_Stop_cb
311 using callback_type = _Callback;
313 template<typename _Cb,
314 enable_if_t<is_constructible_v<_Callback, _Cb>, int> = 0>
316 stop_callback(const stop_token& __token, _Cb&& __cb)
317 noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
318 : _Stop_cb(&_S_execute), _M_cb(std::forward<_Cb>(__cb))
320 if (auto __state = __token._M_state)
322 if (__state->_M_stop_requested())
323 _S_execute(this); // ensures std::terminate on throw
324 else if (__state->_M_register_callback(this))
325 _M_state.swap(__state);
329 template<typename _Cb,
330 enable_if_t<is_constructible_v<_Callback, _Cb>, int> = 0>
332 stop_callback(stop_token&& __token, _Cb&& __cb)
333 noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
334 : _Stop_cb(&_S_execute), _M_cb(std::forward<_Cb>(__cb))
336 if (auto& __state = __token._M_state)
338 if (__state->_M_stop_requested())
339 _S_execute(this); // ensures std::terminate on throw
340 else if (__state->_M_register_callback(this))
341 _M_state.swap(__state);
349 _M_state->_M_remove_callback(this);
353 stop_callback(const stop_callback&) = delete;
354 stop_callback& operator=(const stop_callback&) = delete;
355 stop_callback(stop_callback&&) = delete;
356 stop_callback& operator=(stop_callback&&) = delete;
360 stop_token::_Stop_state _M_state = nullptr;
363 _S_execute(_Stop_cb* __that) noexcept
365 static_cast<stop_callback*>(__that)->_M_cb();
369 template<typename _Callback>
370 stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
372 _GLIBCXX_END_NAMESPACE_VERSION
374 #endif // __cplusplus > 201703L
375 #endif // _GLIBCXX_STOP_TOKEN