Skip to content

Commit 695138c

Browse files
committed
[libc++] implement std::jthread
1 parent 5bdd5d0 commit 695138c

35 files changed

+1299
-11
lines changed

libcxx/docs/UsingLibcxx.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ when ``-fexperimental-library`` is passed:
4848

4949
* The parallel algorithms library (``<execution>`` and the associated algorithms)
5050
* ``std::stop_token``, ``std::stop_source`` and ``std::stop_callback``
51+
* ``std::jthread``
5152
* ``std::chrono::tzdb`` and related time zone functionality
5253
* ``std::ranges::join_view``
5354

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ set(files
677677
__system_error/system_error.h
678678
__thread/formatter.h
679679
__thread/id.h
680+
__thread/jthread.h
680681
__thread/poll_with_backoff.h
681682
__thread/this_thread.h
682683
__thread/thread.h

libcxx/include/__stop_token/atomic_unique_lock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2828
// and LockedBit is the value of State when the lock bit is set, e.g 1 << 2
2929
template <class _State, _State _LockedBit>
3030
class _LIBCPP_AVAILABILITY_SYNC __atomic_unique_lock {
31-
static_assert(std::popcount(_LockedBit) == 1, "LockedBit must be an integer where only one bit is set");
31+
static_assert(std::__libcpp_popcount(static_cast<unsigned long long>(_LockedBit)) == 1,
32+
"LockedBit must be an integer where only one bit is set");
3233

3334
std::atomic<_State>& __state_;
3435
bool __is_locked_;

libcxx/include/__stop_token/stop_callback.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
# pragma GCC system_header
2727
#endif
2828

29+
_LIBCPP_PUSH_MACROS
30+
#include <__undef_macros>
31+
2932
_LIBCPP_BEGIN_NAMESPACE_STD
3033

3134
#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
@@ -96,4 +99,6 @@ _LIBCPP_AVAILABILITY_SYNC stop_callback(stop_token, _Callback) -> stop_callback<
9699

97100
_LIBCPP_END_NAMESPACE_STD
98101

102+
_LIBCPP_POP_MACROS
103+
99104
#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)

libcxx/include/__stop_token/stop_state.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#include <__config>
1515
#include <__stop_token/atomic_unique_lock.h>
1616
#include <__stop_token/intrusive_list_view.h>
17+
#include <__thread/id.h>
1718
#include <atomic>
1819
#include <cstdint>
19-
#include <thread>
2020

2121
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2222
# pragma GCC system_header
@@ -63,7 +63,7 @@ class __stop_state {
6363
using __callback_list = __intrusive_list_view<__stop_callback_base>;
6464

6565
__callback_list __callback_list_;
66-
thread::id __requesting_thread_;
66+
__thread_id __requesting_thread_;
6767

6868
public:
6969
_LIBCPP_HIDE_FROM_ABI __stop_state() noexcept = default;

libcxx/include/__thread/jthread.h

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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___THREAD_JTHREAD_H
11+
#define _LIBCPP___THREAD_JTHREAD_H
12+
13+
#include <__availability>
14+
#include <__config>
15+
#include <__functional/invoke.h>
16+
#include <__stop_token/stop_source.h>
17+
#include <__stop_token/stop_token.h>
18+
#include <__thread/thread.h>
19+
#include <__threading_support>
20+
#include <__type_traits/decay.h>
21+
#include <__type_traits/is_constructible.h>
22+
#include <__type_traits/is_same.h>
23+
#include <__type_traits/remove_cvref.h>
24+
#include <__utility/forward.h>
25+
#include <__utility/move.h>
26+
27+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28+
# pragma GCC system_header
29+
#endif
30+
31+
#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
32+
33+
_LIBCPP_BEGIN_NAMESPACE_STD
34+
35+
class _LIBCPP_AVAILABILITY_SYNC jthread {
36+
public:
37+
// types
38+
using id = thread::id;
39+
using native_handle_type = thread::native_handle_type;
40+
41+
// [thread.jthread.cons], constructors, move, and assignment
42+
_LIBCPP_HIDE_FROM_ABI jthread() noexcept : __stop_source_(std::nostopstate) {}
43+
44+
template <class _Fun, class... _Args>
45+
_LIBCPP_HIDE_FROM_ABI explicit jthread(_Fun&& __fun, _Args&&... __args)
46+
requires(!std::is_same_v<remove_cvref_t<_Fun>, jthread>)
47+
: __stop_source_(),
48+
__thread_(__init_thread(__stop_source_, std::forward<_Fun>(__fun), std::forward<_Args>(__args)...)) {
49+
static_assert(is_constructible_v<decay_t<_Fun>, _Fun>);
50+
static_assert((is_constructible_v<decay_t<_Args>, _Args> && ...));
51+
static_assert(is_invocable_v<decay_t<_Fun>, decay_t<_Args>...> ||
52+
is_invocable_v<decay_t<_Fun>, stop_token, decay_t<_Args>...>);
53+
}
54+
55+
_LIBCPP_HIDE_FROM_ABI ~jthread() {
56+
if (joinable()) {
57+
request_stop();
58+
join();
59+
}
60+
}
61+
62+
jthread(const jthread&) = delete;
63+
64+
_LIBCPP_HIDE_FROM_ABI jthread(jthread&&) noexcept = default;
65+
66+
jthread& operator=(const jthread&) = delete;
67+
68+
_LIBCPP_HIDE_FROM_ABI jthread& operator=(jthread&& __other) noexcept {
69+
if (this != &__other) {
70+
if (joinable()) {
71+
request_stop();
72+
join();
73+
}
74+
__stop_source_ = std::move(__other.__stop_source_);
75+
__thread_ = std::move(__other.__thread_);
76+
}
77+
78+
return *this;
79+
}
80+
81+
// [thread.jthread.mem], members
82+
_LIBCPP_HIDE_FROM_ABI void swap(jthread& __other) noexcept {
83+
std::swap(__stop_source_, __other.__stop_source_);
84+
std::swap(__thread_, __other.__thread_);
85+
}
86+
87+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool joinable() const noexcept { return get_id() != id(); }
88+
89+
_LIBCPP_HIDE_FROM_ABI void join() { __thread_.join(); }
90+
91+
_LIBCPP_HIDE_FROM_ABI void detach() { __thread_.detach(); }
92+
93+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI id get_id() const noexcept { return __thread_.get_id(); }
94+
95+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __thread_.native_handle(); }
96+
97+
// [thread.jthread.stop], stop token handling
98+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_source get_stop_source() noexcept { return __stop_source_; }
99+
100+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_token get_stop_token() const noexcept { return __stop_source_.get_token(); }
101+
102+
_LIBCPP_HIDE_FROM_ABI bool request_stop() noexcept { return __stop_source_.request_stop(); }
103+
104+
// [thread.jthread.special], specialized algorithms
105+
_LIBCPP_HIDE_FROM_ABI friend void swap(jthread& __lhs, jthread& __rhs) noexcept { __lhs.swap(__rhs); }
106+
107+
// [thread.jthread.static], static members
108+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static unsigned int hardware_concurrency() noexcept {
109+
return thread::hardware_concurrency();
110+
}
111+
112+
private:
113+
template <class _Fun, class... _Args>
114+
_LIBCPP_HIDE_FROM_ABI static thread __init_thread(const stop_source& __ss, _Fun&& __fun, _Args&&... __args) {
115+
if constexpr (is_invocable_v<decay_t<_Fun>, stop_token, decay_t<_Args>...>) {
116+
return thread(std::forward<_Fun>(__fun), __ss.get_token(), std::forward<_Args>(__args)...);
117+
} else {
118+
return thread(std::forward<_Fun>(__fun), std::forward<_Args>(__args)...);
119+
}
120+
}
121+
122+
stop_source __stop_source_;
123+
thread __thread_;
124+
};
125+
126+
_LIBCPP_END_NAMESPACE_STD
127+
128+
#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
129+
130+
#endif // _LIBCPP___THREAD_JTHREAD_H

libcxx/include/module.modulemap.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,10 @@ module std_private_system_error_system_error [system] { header "__system_erro
17891789

17901790
module std_private_thread_formatter [system] { header "__thread/formatter.h" }
17911791
module std_private_thread_id [system] { header "__thread/id.h" }
1792+
module std_private_thread_jthread [system] {
1793+
header "__thread/jthread.h"
1794+
export *
1795+
}
17921796
module std_private_thread_poll_with_backoff [system] { header "__thread/poll_with_backoff.h" }
17931797
module std_private_thread_this_thread [system] { header "__thread/this_thread.h" }
17941798
module std_private_thread_thread [system] {

libcxx/include/thread

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void sleep_for(const chrono::duration<Rep, Period>& rel_time);
9090
#include <__availability>
9191
#include <__config>
9292
#include <__thread/formatter.h>
93+
#include <__thread/jthread.h>
9394
#include <__thread/this_thread.h>
9495
#include <__thread/thread.h>
9596
#include <__threading_support>

libcxx/modules/std/thread.inc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ export namespace std {
1515
using std::swap;
1616

1717
// [thread.jthread.class], class jthread
18-
// using std::jthread;
18+
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
19+
using std::jthread;
20+
# endif
1921

2022
// [thread.thread.this], namespace this_thread
2123
namespace this_thread {

libcxx/test/libcxx/transitive_includes/cxx03.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,9 +805,9 @@ stop_token cstddef
805805
stop_token cstdint
806806
stop_token cstring
807807
stop_token ctime
808+
stop_token iosfwd
808809
stop_token limits
809810
stop_token ratio
810-
stop_token thread
811811
stop_token type_traits
812812
stop_token version
813813
streambuf cstdint
@@ -867,6 +867,7 @@ system_error string
867867
system_error type_traits
868868
system_error version
869869
thread array
870+
thread atomic
870871
thread cerrno
871872
thread chrono
872873
thread compare

libcxx/test/libcxx/transitive_includes/cxx11.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,9 +811,9 @@ stop_token cstddef
811811
stop_token cstdint
812812
stop_token cstring
813813
stop_token ctime
814+
stop_token iosfwd
814815
stop_token limits
815816
stop_token ratio
816-
stop_token thread
817817
stop_token type_traits
818818
stop_token version
819819
streambuf cstdint
@@ -873,6 +873,7 @@ system_error string
873873
system_error type_traits
874874
system_error version
875875
thread array
876+
thread atomic
876877
thread cerrno
877878
thread chrono
878879
thread compare

libcxx/test/libcxx/transitive_includes/cxx14.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,9 @@ stop_token cstddef
813813
stop_token cstdint
814814
stop_token cstring
815815
stop_token ctime
816+
stop_token iosfwd
816817
stop_token limits
817818
stop_token ratio
818-
stop_token thread
819819
stop_token type_traits
820820
stop_token version
821821
streambuf cstdint
@@ -875,6 +875,7 @@ system_error string
875875
system_error type_traits
876876
system_error version
877877
thread array
878+
thread atomic
878879
thread cerrno
879880
thread chrono
880881
thread compare

libcxx/test/libcxx/transitive_includes/cxx17.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,9 @@ stop_token cstddef
813813
stop_token cstdint
814814
stop_token cstring
815815
stop_token ctime
816+
stop_token iosfwd
816817
stop_token limits
817818
stop_token ratio
818-
stop_token thread
819819
stop_token type_traits
820820
stop_token version
821821
streambuf cstdint
@@ -875,6 +875,7 @@ system_error string
875875
system_error type_traits
876876
system_error version
877877
thread array
878+
thread atomic
878879
thread cerrno
879880
thread chrono
880881
thread compare

libcxx/test/libcxx/transitive_includes/cxx20.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,9 +818,9 @@ stop_token cstddef
818818
stop_token cstdint
819819
stop_token cstring
820820
stop_token ctime
821+
stop_token iosfwd
821822
stop_token limits
822823
stop_token ratio
823-
stop_token thread
824824
stop_token type_traits
825825
stop_token version
826826
streambuf cstdint
@@ -880,6 +880,7 @@ system_error string
880880
system_error type_traits
881881
system_error version
882882
thread array
883+
thread atomic
883884
thread cerrno
884885
thread compare
885886
thread cstddef

libcxx/test/libcxx/transitive_includes/cxx23.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,9 +582,9 @@ stop_token cstddef
582582
stop_token cstdint
583583
stop_token cstring
584584
stop_token ctime
585+
stop_token iosfwd
585586
stop_token limits
586587
stop_token ratio
587-
stop_token thread
588588
stop_token version
589589
streambuf cstdint
590590
streambuf ios
@@ -627,6 +627,7 @@ system_error stdexcept
627627
system_error string
628628
system_error version
629629
thread array
630+
thread atomic
630631
thread cerrno
631632
thread compare
632633
thread cstddef

libcxx/test/libcxx/transitive_includes/cxx26.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,9 +582,9 @@ stop_token cstddef
582582
stop_token cstdint
583583
stop_token cstring
584584
stop_token ctime
585+
stop_token iosfwd
585586
stop_token limits
586587
stop_token ratio
587-
stop_token thread
588588
stop_token version
589589
streambuf cstdint
590590
streambuf ios
@@ -627,6 +627,7 @@ system_error stdexcept
627627
system_error string
628628
system_error version
629629
thread array
630+
thread atomic
630631
thread cerrno
631632
thread compare
632633
thread cstddef

0 commit comments

Comments
 (0)