2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___THREAD_THREAD_H
11 #define _LIBCPP___THREAD_THREAD_H
13 #include <__condition_variable/condition_variable.h>
15 #include <__exception/terminate.h>
16 #include <__functional/hash.h>
17 #include <__functional/unary_function.h>
18 #include <__memory/unique_ptr.h>
19 #include <__mutex/mutex.h>
20 #include <__system_error/system_error.h>
21 #include <__thread/id.h>
22 #include <__thread/support.h>
23 #include <__utility/forward.h>
26 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
31 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
32 # pragma GCC system_header
36 #include <__undef_macros>
38 _LIBCPP_BEGIN_NAMESPACE_STD
41 class __thread_specific_ptr
;
42 class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
;
43 class _LIBCPP_HIDDEN __thread_struct_imp
;
44 class __assoc_sub_state
;
46 _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr
<__thread_struct
>& __thread_local_data();
48 class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
{
49 __thread_struct_imp
* __p_
;
51 __thread_struct(const __thread_struct
&);
52 __thread_struct
& operator=(const __thread_struct
&);
58 void notify_all_at_thread_exit(condition_variable
*, mutex
*);
59 void __make_ready_at_thread_exit(__assoc_sub_state
*);
63 class __thread_specific_ptr
{
64 __libcpp_tls_key __key_
;
66 // Only __thread_local_data() may construct a __thread_specific_ptr
67 // and only with _Tp == __thread_struct.
68 static_assert(is_same
<_Tp
, __thread_struct
>::value
, "");
69 __thread_specific_ptr();
70 friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr
<__thread_struct
>& __thread_local_data();
72 _LIBCPP_HIDDEN
static void _LIBCPP_TLS_DESTRUCTOR_CC
__at_thread_exit(void*);
77 __thread_specific_ptr(const __thread_specific_ptr
&) = delete;
78 __thread_specific_ptr
& operator=(const __thread_specific_ptr
&) = delete;
79 ~__thread_specific_ptr();
81 _LIBCPP_HIDE_FROM_ABI pointer
get() const { return static_cast<_Tp
*>(__libcpp_tls_get(__key_
)); }
82 _LIBCPP_HIDE_FROM_ABI pointer
operator*() const { return *get(); }
83 _LIBCPP_HIDE_FROM_ABI pointer
operator->() const { return get(); }
84 void set_pointer(pointer __p
);
88 void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr
<_Tp
>::__at_thread_exit(void* __p
) {
89 delete static_cast<pointer
>(__p
);
93 __thread_specific_ptr
<_Tp
>::__thread_specific_ptr() {
94 int __ec
= __libcpp_tls_create(&__key_
, &__thread_specific_ptr::__at_thread_exit
);
96 __throw_system_error(__ec
, "__thread_specific_ptr construction failed");
100 __thread_specific_ptr
<_Tp
>::~__thread_specific_ptr() {
101 // __thread_specific_ptr is only created with a static storage duration
102 // so this destructor is only invoked during program termination. Invoking
103 // pthread_key_delete(__key_) may prevent other threads from deleting their
104 // thread local data. For this reason we leak the key.
108 void __thread_specific_ptr
<_Tp
>::set_pointer(pointer __p
) {
109 _LIBCPP_ASSERT_INTERNAL(get() == nullptr, "Attempting to overwrite thread local data");
110 std::__libcpp_tls_set(__key_
, __p
);
114 struct _LIBCPP_TEMPLATE_VIS hash
<__thread_id
> : public __unary_function
<__thread_id
, size_t> {
115 _LIBCPP_HIDE_FROM_ABI
size_t operator()(__thread_id __v
) const _NOEXCEPT
{
116 return hash
<__libcpp_thread_id
>()(__v
.__id_
);
120 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
121 template <class _CharT
, class _Traits
>
122 _LIBCPP_HIDE_FROM_ABI basic_ostream
<_CharT
, _Traits
>&
123 operator<<(basic_ostream
<_CharT
, _Traits
>& __os
, __thread_id __id
) {
124 // [thread.thread.id]/9
125 // Effects: Inserts the text representation for charT of id into out.
127 // [thread.thread.id]/2
128 // The text representation for the character type charT of an
129 // object of type thread::id is an unspecified sequence of charT
130 // such that, for two objects of type thread::id x and y, if
131 // x == y is true, the thread::id objects have the same text
132 // representation, and if x != y is true, the thread::id objects
133 // have distinct text representations.
135 // Since various flags in the output stream can affect how the
136 // thread id is represented (e.g. numpunct or showbase), we
137 // use a temporary stream instead and just output the thread
138 // id representation as a string.
140 basic_ostringstream
<_CharT
, _Traits
> __sstr
;
141 __sstr
.imbue(locale::classic());
142 __sstr
<< __id
.__id_
;
143 return __os
<< __sstr
.str();
145 #endif // _LIBCPP_HAS_NO_LOCALIZATION
147 class _LIBCPP_EXPORTED_FROM_ABI thread
{
148 __libcpp_thread_t __t_
;
150 thread(const thread
&);
151 thread
& operator=(const thread
&);
154 typedef __thread_id id
;
155 typedef __libcpp_thread_t native_handle_type
;
157 _LIBCPP_HIDE_FROM_ABI
thread() _NOEXCEPT
: __t_(_LIBCPP_NULL_THREAD
) {}
158 #ifndef _LIBCPP_CXX03_LANG
159 template <class _Fp
, class... _Args
, __enable_if_t
<!is_same
<__remove_cvref_t
<_Fp
>, thread
>::value
, int> = 0>
160 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
explicit thread(_Fp
&& __f
, _Args
&&... __args
);
161 #else // _LIBCPP_CXX03_LANG
163 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
explicit thread(_Fp __f
);
167 _LIBCPP_HIDE_FROM_ABI
thread(thread
&& __t
) _NOEXCEPT
: __t_(__t
.__t_
) { __t
.__t_
= _LIBCPP_NULL_THREAD
; }
169 _LIBCPP_HIDE_FROM_ABI thread
& operator=(thread
&& __t
) _NOEXCEPT
{
170 if (!__libcpp_thread_isnull(&__t_
))
173 __t
.__t_
= _LIBCPP_NULL_THREAD
;
177 _LIBCPP_HIDE_FROM_ABI
void swap(thread
& __t
) _NOEXCEPT
{ std::swap(__t_
, __t
.__t_
); }
179 _LIBCPP_HIDE_FROM_ABI
bool joinable() const _NOEXCEPT
{ return !__libcpp_thread_isnull(&__t_
); }
182 _LIBCPP_HIDE_FROM_ABI id
get_id() const _NOEXCEPT
{ return __libcpp_thread_get_id(&__t_
); }
183 _LIBCPP_HIDE_FROM_ABI native_handle_type
native_handle() _NOEXCEPT
{ return __t_
; }
185 static unsigned hardware_concurrency() _NOEXCEPT
;
188 #ifndef _LIBCPP_CXX03_LANG
190 template <class _TSp
, class _Fp
, class... _Args
, size_t... _Indices
>
191 inline _LIBCPP_HIDE_FROM_ABI
void __thread_execute(tuple
<_TSp
, _Fp
, _Args
...>& __t
, __tuple_indices
<_Indices
...>) {
192 std::__invoke(std::move(std::get
<1>(__t
)), std::move(std::get
<_Indices
>(__t
))...);
196 _LIBCPP_HIDE_FROM_ABI
void* __thread_proxy(void* __vp
) {
197 // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
198 unique_ptr
<_Fp
> __p(static_cast<_Fp
*>(__vp
));
199 __thread_local_data().set_pointer(std::get
<0>(*__p
.get()).release());
200 typedef typename __make_tuple_indices
<tuple_size
<_Fp
>::value
, 2>::type _Index
;
201 std::__thread_execute(*__p
.get(), _Index());
205 template <class _Fp
, class... _Args
, __enable_if_t
<!is_same
<__remove_cvref_t
<_Fp
>, thread
>::value
, int> >
206 thread::thread(_Fp
&& __f
, _Args
&&... __args
) {
207 typedef unique_ptr
<__thread_struct
> _TSPtr
;
208 _TSPtr
__tsp(new __thread_struct
);
209 typedef tuple
<_TSPtr
, __decay_t
<_Fp
>, __decay_t
<_Args
>...> _Gp
;
210 unique_ptr
<_Gp
> __p(new _Gp(std::move(__tsp
), std::forward
<_Fp
>(__f
), std::forward
<_Args
>(__args
)...));
211 int __ec
= std::__libcpp_thread_create(&__t_
, &__thread_proxy
<_Gp
>, __p
.get());
215 __throw_system_error(__ec
, "thread constructor failed");
218 #else // _LIBCPP_CXX03_LANG
221 struct __thread_invoke_pair
{
222 // This type is used to pass memory for thread local storage and a functor
223 // to a newly created thread because std::pair doesn't work with
224 // std::unique_ptr in C++03.
225 _LIBCPP_HIDE_FROM_ABI
__thread_invoke_pair(_Fp
& __f
) : __tsp_(new __thread_struct
), __fn_(__f
) {}
226 unique_ptr
<__thread_struct
> __tsp_
;
231 _LIBCPP_HIDE_FROM_ABI
void* __thread_proxy_cxx03(void* __vp
) {
232 unique_ptr
<_Fp
> __p(static_cast<_Fp
*>(__vp
));
233 __thread_local_data().set_pointer(__p
->__tsp_
.release());
239 thread::thread(_Fp __f
) {
240 typedef __thread_invoke_pair
<_Fp
> _InvokePair
;
241 typedef unique_ptr
<_InvokePair
> _PairPtr
;
242 _PairPtr
__pp(new _InvokePair(__f
));
243 int __ec
= std::__libcpp_thread_create(&__t_
, &__thread_proxy_cxx03
<_InvokePair
>, __pp
.get());
247 __throw_system_error(__ec
, "thread constructor failed");
250 #endif // _LIBCPP_CXX03_LANG
252 inline _LIBCPP_HIDE_FROM_ABI
void swap(thread
& __x
, thread
& __y
) _NOEXCEPT
{ __x
.swap(__y
); }
254 _LIBCPP_END_NAMESPACE_STD
258 #endif // _LIBCPP___THREAD_THREAD_H