Skip to content

Commit b77e50e

Browse files
committed
[libc++] Implement stop_token
Implement stop_token http://eel.is/c++draft/thread.stoptoken
1 parent 8b7f379 commit b77e50e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+3097
-68
lines changed

libcxx/docs/Status/Cxx20.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Paper Status
5050
.. [#note-P0883.2] P0883: ``ATOMIC_FLAG_INIT`` was marked deprecated in version 14.0, but was undeprecated with the implementation of LWG3659 in version 15.0.
5151
.. [#note-P2231] P2231: Optional is complete. The changes to variant haven't been implemented yet.
5252
.. [#note-P0408] P0408: Only `view()` members implemented.
53+
.. [#note-P0660] P0660: Section 32.3 Stop Tokens is complete. ``jthread`` hasn't been implemented yet.
5354
5455
.. _issues-status-cxx20:
5556

libcxx/docs/Status/Cxx20Issues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@
210210
"`3250 <https://wg21.link/LWG3250>`__","``std::format``\ : ``#``\ (alternate form) for NaN and inf","Prague","|Complete|","14.0","|format|"
211211
"`3251 <https://wg21.link/LWG3251>`__","Are ``std::format``\ alignment specifiers applied to string arguments?","Prague","|Complete|","14.0","|format|"
212212
"`3252 <https://wg21.link/LWG3252>`__","Parse locale's aware modifiers for commands are not consistent with POSIX spec","Prague","","","|chrono|"
213-
"`3254 <https://wg21.link/LWG3254>`__","Strike ``stop_token``\ 's ``operator!=``\ ","Prague","",""
213+
"`3254 <https://wg21.link/LWG3254>`__","Strike ``stop_token``\ 's ``operator!=``\ ","Prague","|Complete|","17.0"
214214
"`3255 <https://wg21.link/LWG3255>`__","``span``\ 's ``array``\ constructor is too strict","Prague","|Complete|",""
215215
"`3260 <https://wg21.link/LWG3260>`__","``year_month*``\ arithmetic rejects durations convertible to years","Prague","","","|chrono|"
216216
"`3262 <https://wg21.link/LWG3262>`__","Formatting of negative durations is not specified","Prague","|Complete|","16.0","|chrono| |format|"

libcxx/docs/Status/Cxx20Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
"`P0553R4 <https://wg21.link/P0553R4>`__","LWG","Bit operations","Cologne","|Complete|","9.0"
105105
"`P0631R8 <https://wg21.link/P0631R8>`__","LWG","Math Constants","Cologne","|Complete|","11.0"
106106
"`P0645R10 <https://wg21.link/P0645R10>`__","LWG","Text Formatting","Cologne","|Complete| [#note-P0645]_","14.0"
107-
"`P0660R10 <https://wg21.link/P0660R10>`__","LWG","Stop Token and Joining Thread, Rev 10","Cologne","",""
107+
"`P0660R10 <https://wg21.link/P0660R10>`__","LWG","Stop Token and Joining Thread, Rev 10.","Cologne","|In Progress| [#note-P0660]_",""
108108
"`P0784R7 <https://wg21.link/P0784R7>`__","CWG","More constexpr containers","Cologne","|Complete|","12.0"
109109
"`P0980R1 <https://wg21.link/P0980R1>`__","LWG","Making std::string constexpr","Cologne","|Complete|","15.0"
110110
"`P1004R2 <https://wg21.link/P1004R2>`__","LWG","Making std::vector constexpr","Cologne","|Complete|","15.0"

libcxx/include/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ set(files
642642
__stop_token/atomic_unique_lock.h
643643
__stop_token/intrusive_list_view.h
644644
__stop_token/intrusive_shared_ptr.h
645+
__stop_token/stop_callback.h
646+
__stop_token/stop_source.h
647+
__stop_token/stop_state.h
648+
__stop_token/stop_token.h
645649
__string/char_traits.h
646650
__string/constexpr_c_functions.h
647651
__string/extern_template_lists.h
@@ -959,6 +963,7 @@ set(files
959963
stdint.h
960964
stdio.h
961965
stdlib.h
966+
stop_token
962967
streambuf
963968
string
964969
string.h

libcxx/include/__stop_token/atomic_unique_lock.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2727
// where State contains a lock bit and might contain other data,
2828
// and LockedBit is the value of State when the lock bit is set, e.g 1 << 2
2929
template <class _State, _State _LockedBit>
30-
class __atomic_unique_lock {
30+
class _LIBCPP_AVAILABILITY_SYNC __atomic_unique_lock {
3131
static_assert(std::popcount(_LockedBit) == 1, "LockedBit must be an integer where only one bit is set");
3232

3333
std::atomic<_State>& __state_;
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___STOP_TOKEN_STOP_CALLBACK_H
11+
#define _LIBCPP___STOP_TOKEN_STOP_CALLBACK_H
12+
13+
#include <__availability>
14+
#include <__concepts/constructible.h>
15+
#include <__concepts/destructible.h>
16+
#include <__concepts/invocable.h>
17+
#include <__config>
18+
#include <__stop_token/intrusive_shared_ptr.h>
19+
#include <__stop_token/stop_state.h>
20+
#include <__stop_token/stop_token.h>
21+
#include <__type_traits/is_nothrow_constructible.h>
22+
#include <__utility/forward.h>
23+
#include <__utility/move.h>
24+
25+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26+
# pragma GCC system_header
27+
#endif
28+
29+
_LIBCPP_BEGIN_NAMESPACE_STD
30+
31+
#if _LIBCPP_STD_VER >= 20
32+
33+
template <class _Callback>
34+
class _LIBCPP_AVAILABILITY_SYNC stop_callback : private __stop_callback_base {
35+
static_assert(invocable<_Callback>,
36+
"Mandates: stop_callback is instantiated with an argument for the template parameter Callback that "
37+
"satisfies invocable.");
38+
static_assert(destructible<_Callback>,
39+
"Mandates: stop_callback is instantiated with an argument for the template parameter Callback that "
40+
"satisfies destructible.");
41+
42+
public:
43+
using callback_type = _Callback;
44+
45+
template <class _Cb>
46+
requires constructible_from<_Callback, _Cb>
47+
_LIBCPP_HIDE_FROM_ABI explicit stop_callback(const stop_token& __st,
48+
_Cb&& __cb) noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
49+
: stop_callback(__private_tag{}, __st.__state_, std::forward<_Cb>(__cb)) {}
50+
51+
template <class _Cb>
52+
requires constructible_from<_Callback, _Cb>
53+
_LIBCPP_HIDE_FROM_ABI explicit stop_callback(stop_token&& __st,
54+
_Cb&& __cb) noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
55+
: stop_callback(__private_tag{}, std::move(__st.__state_), std::forward<_Cb>(__cb)) {}
56+
57+
_LIBCPP_HIDE_FROM_ABI ~stop_callback() {
58+
if (__state_) {
59+
__state_->__remove_callback(this);
60+
}
61+
}
62+
63+
stop_callback(const stop_callback&) = delete;
64+
stop_callback(stop_callback&&) = delete;
65+
stop_callback& operator=(const stop_callback&) = delete;
66+
stop_callback& operator=(stop_callback&&) = delete;
67+
68+
private:
69+
_LIBCPP_NO_UNIQUE_ADDRESS _Callback __callback_;
70+
__intrusive_shared_ptr<__stop_state> __state_;
71+
72+
friend __stop_callback_base;
73+
74+
struct __private_tag {};
75+
76+
template <class _StatePtr, class _Cb>
77+
_LIBCPP_HIDE_FROM_ABI explicit stop_callback(__private_tag, _StatePtr&& __state, _Cb&& __cb) noexcept(
78+
is_nothrow_constructible_v<_Callback, _Cb>)
79+
: __stop_callback_base([](__stop_callback_base* __cb_base) noexcept {
80+
// stop callback is supposed to only be called once
81+
std::forward<_Callback>(static_cast<stop_callback*>(__cb_base)->__callback_)();
82+
}),
83+
__callback_(std::forward<_Cb>(__cb)),
84+
__state_() {
85+
if (__state && __state->__add_callback(this)) {
86+
// st.stop_requested() was false and this is successfully added to the linked list
87+
__state_ = std::forward<_StatePtr>(__state);
88+
}
89+
}
90+
};
91+
92+
template <class Callback>
93+
_LIBCPP_AVAILABILITY_SYNC stop_callback(stop_token, Callback) -> stop_callback<Callback>;
94+
95+
#endif // _LIBCPP_STD_VER >= 20
96+
97+
_LIBCPP_END_NAMESPACE_STD
98+
99+
#endif // _LIBCPP___STOP_TOKEN_STOP_TOKEN_H
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___STOP_TOKEN_STOP_SOURCE_H
11+
#define _LIBCPP___STOP_TOKEN_STOP_SOURCE_H
12+
13+
#include <__availability>
14+
#include <__config>
15+
#include <__stop_token/intrusive_shared_ptr.h>
16+
#include <__stop_token/stop_state.h>
17+
#include <__stop_token/stop_token.h>
18+
#include <__utility/move.h>
19+
20+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21+
# pragma GCC system_header
22+
#endif
23+
24+
_LIBCPP_BEGIN_NAMESPACE_STD
25+
26+
#if _LIBCPP_STD_VER >= 20
27+
28+
struct nostopstate_t {
29+
explicit nostopstate_t() = default;
30+
};
31+
32+
inline constexpr nostopstate_t nostopstate{};
33+
34+
class _LIBCPP_AVAILABILITY_SYNC stop_source {
35+
public:
36+
_LIBCPP_HIDE_FROM_ABI stop_source() : __state_(new __stop_state()) { __state_->__increment_stop_source_counter(); }
37+
38+
_LIBCPP_HIDE_FROM_ABI explicit stop_source(nostopstate_t) noexcept : __state_(nullptr) {}
39+
40+
_LIBCPP_HIDE_FROM_ABI stop_source(const stop_source& __other) noexcept : __state_(__other.__state_) {
41+
if (__state_) {
42+
__state_->__increment_stop_source_counter();
43+
}
44+
}
45+
46+
_LIBCPP_HIDE_FROM_ABI stop_source(stop_source&& __other) noexcept = default;
47+
48+
_LIBCPP_HIDE_FROM_ABI stop_source& operator=(const stop_source& __other) noexcept {
49+
// increment `__other` first so that we don't hit 0 in case of self-assignment
50+
if (__other.__state_) {
51+
__other.__state_->__increment_stop_source_counter();
52+
}
53+
if (__state_) {
54+
__state_->__decrement_stop_source_counter();
55+
}
56+
__state_ = __other.__state_;
57+
return *this;
58+
}
59+
60+
_LIBCPP_HIDE_FROM_ABI stop_source& operator=(stop_source&&) noexcept = default;
61+
62+
_LIBCPP_HIDE_FROM_ABI ~stop_source() {
63+
if (__state_) {
64+
__state_->__decrement_stop_source_counter();
65+
}
66+
}
67+
68+
_LIBCPP_HIDE_FROM_ABI void swap(stop_source& __other) noexcept { __state_.swap(__other.__state_); }
69+
70+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_token get_token() const noexcept { return stop_token(__state_); }
71+
72+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool stop_possible() const noexcept { return __state_ != nullptr; }
73+
74+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool stop_requested() const noexcept {
75+
return __state_ != nullptr && __state_->__stop_requested();
76+
}
77+
78+
_LIBCPP_HIDE_FROM_ABI bool request_stop() noexcept { return __state_ && __state_->__request_stop(); }
79+
80+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend bool operator==(const stop_source&, const stop_source&) noexcept = default;
81+
82+
_LIBCPP_HIDE_FROM_ABI friend void swap(stop_source& __lhs, stop_source& __rhs) noexcept { __lhs.swap(__rhs); }
83+
84+
private:
85+
__intrusive_shared_ptr<__stop_state> __state_;
86+
};
87+
88+
#endif // _LIBCPP_STD_VER >= 20
89+
90+
_LIBCPP_END_NAMESPACE_STD
91+
92+
#endif // _LIBCPP___STOP_TOKEN_STOP_SOURCE_H

0 commit comments

Comments
 (0)