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 <__threading_support>
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
35 _LIBCPP_BEGIN_NAMESPACE_STD
37 template <class _Tp
> class __thread_specific_ptr
;
38 class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
;
39 class _LIBCPP_HIDDEN __thread_struct_imp
;
40 class __assoc_sub_state
;
42 _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr
<__thread_struct
>& __thread_local_data();
44 class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
46 __thread_struct_imp
* __p_
;
48 __thread_struct(const __thread_struct
&);
49 __thread_struct
& operator=(const __thread_struct
&);
54 void notify_all_at_thread_exit(condition_variable
*, mutex
*);
55 void __make_ready_at_thread_exit(__assoc_sub_state
*);
59 class __thread_specific_ptr
61 __libcpp_tls_key __key_
;
63 // Only __thread_local_data() may construct a __thread_specific_ptr
64 // and only with _Tp == __thread_struct.
65 static_assert((is_same
<_Tp
, __thread_struct
>::value
), "");
66 __thread_specific_ptr();
67 friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr
<__thread_struct
>& __thread_local_data();
69 __thread_specific_ptr(const __thread_specific_ptr
&);
70 __thread_specific_ptr
& operator=(const __thread_specific_ptr
&);
72 _LIBCPP_HIDDEN
static void _LIBCPP_TLS_DESTRUCTOR_CC
__at_thread_exit(void*);
77 ~__thread_specific_ptr();
79 _LIBCPP_INLINE_VISIBILITY
80 pointer
get() const {return static_cast<_Tp
*>(__libcpp_tls_get(__key_
));}
81 _LIBCPP_INLINE_VISIBILITY
82 pointer
operator*() const {return *get();}
83 _LIBCPP_INLINE_VISIBILITY
84 pointer
operator->() const {return get();}
85 void set_pointer(pointer __p
);
89 void _LIBCPP_TLS_DESTRUCTOR_CC
90 __thread_specific_ptr
<_Tp
>::__at_thread_exit(void* __p
)
92 delete static_cast<pointer
>(__p
);
96 __thread_specific_ptr
<_Tp
>::__thread_specific_ptr()
99 __libcpp_tls_create(&__key_
, &__thread_specific_ptr::__at_thread_exit
);
101 __throw_system_error(__ec
, "__thread_specific_ptr construction failed");
105 __thread_specific_ptr
<_Tp
>::~__thread_specific_ptr()
107 // __thread_specific_ptr is only created with a static storage duration
108 // so this destructor is only invoked during program termination. Invoking
109 // pthread_key_delete(__key_) may prevent other threads from deleting their
110 // thread local data. For this reason we leak the key.
115 __thread_specific_ptr
<_Tp
>::set_pointer(pointer __p
)
117 _LIBCPP_ASSERT_UNCATEGORIZED(get() == nullptr,
118 "Attempting to overwrite thread local data");
119 std::__libcpp_tls_set(__key_
, __p
);
123 struct _LIBCPP_TEMPLATE_VIS hash
<__thread_id
>
124 : public __unary_function
<__thread_id
, size_t>
126 _LIBCPP_INLINE_VISIBILITY
127 size_t operator()(__thread_id __v
) const _NOEXCEPT
129 return hash
<__libcpp_thread_id
>()(__v
.__id_
);
133 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
134 template <class _CharT
, class _Traits
>
135 _LIBCPP_INLINE_VISIBILITY basic_ostream
<_CharT
, _Traits
>&
136 operator<<(basic_ostream
<_CharT
, _Traits
>& __os
, __thread_id __id
) {
137 // [thread.thread.id]/9
138 // Effects: Inserts the text representation for charT of id into out.
140 // [thread.thread.id]/2
141 // The text representation for the character type charT of an
142 // object of type thread::id is an unspecified sequence of charT
143 // such that, for two objects of type thread::id x and y, if
144 // x == y is true, the thread::id objects have the same text
145 // representation, and if x != y is true, the thread::id objects
146 // have distinct text representations.
148 // Since various flags in the output stream can affect how the
149 // thread id is represented (e.g. numpunct or showbase), we
150 // use a temporary stream instead and just output the thread
151 // id representation as a string.
153 basic_ostringstream
<_CharT
, _Traits
> __sstr
;
154 __sstr
.imbue(locale::classic());
155 __sstr
<< __id
.__id_
;
156 return __os
<< __sstr
.str();
158 #endif // _LIBCPP_HAS_NO_LOCALIZATION
160 class _LIBCPP_EXPORTED_FROM_ABI thread
162 __libcpp_thread_t __t_
;
164 thread(const thread
&);
165 thread
& operator=(const thread
&);
167 typedef __thread_id id
;
168 typedef __libcpp_thread_t native_handle_type
;
170 _LIBCPP_INLINE_VISIBILITY
171 thread() _NOEXCEPT
: __t_(_LIBCPP_NULL_THREAD
) {}
172 #ifndef _LIBCPP_CXX03_LANG
173 template <class _Fp
, class ..._Args
,
174 class = __enable_if_t
<!is_same
<__remove_cvref_t
<_Fp
>, thread
>::value
> >
175 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
176 explicit thread(_Fp
&& __f
, _Args
&&... __args
);
177 #else // _LIBCPP_CXX03_LANG
179 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
180 explicit thread(_Fp __f
);
184 _LIBCPP_INLINE_VISIBILITY
185 thread(thread
&& __t
) _NOEXCEPT
: __t_(__t
.__t_
) {
186 __t
.__t_
= _LIBCPP_NULL_THREAD
;
189 _LIBCPP_INLINE_VISIBILITY
190 thread
& operator=(thread
&& __t
) _NOEXCEPT
{
191 if (!__libcpp_thread_isnull(&__t_
))
194 __t
.__t_
= _LIBCPP_NULL_THREAD
;
198 _LIBCPP_INLINE_VISIBILITY
199 void swap(thread
& __t
) _NOEXCEPT
{_VSTD::swap(__t_
, __t
.__t_
);}
201 _LIBCPP_INLINE_VISIBILITY
202 bool joinable() const _NOEXCEPT
{return !__libcpp_thread_isnull(&__t_
);}
205 _LIBCPP_INLINE_VISIBILITY
206 id
get_id() const _NOEXCEPT
{return __libcpp_thread_get_id(&__t_
);}
207 _LIBCPP_INLINE_VISIBILITY
208 native_handle_type
native_handle() _NOEXCEPT
{return __t_
;}
210 static unsigned hardware_concurrency() _NOEXCEPT
;
213 #ifndef _LIBCPP_CXX03_LANG
215 template <class _TSp
, class _Fp
, class ..._Args
, size_t ..._Indices
>
216 inline _LIBCPP_INLINE_VISIBILITY
218 __thread_execute(tuple
<_TSp
, _Fp
, _Args
...>& __t
, __tuple_indices
<_Indices
...>)
220 _VSTD::__invoke(_VSTD::move(_VSTD::get
<1>(__t
)), _VSTD::move(_VSTD::get
<_Indices
>(__t
))...);
224 _LIBCPP_INLINE_VISIBILITY
225 void* __thread_proxy(void* __vp
)
227 // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
228 unique_ptr
<_Fp
> __p(static_cast<_Fp
*>(__vp
));
229 __thread_local_data().set_pointer(_VSTD::get
<0>(*__p
.get()).release());
230 typedef typename __make_tuple_indices
<tuple_size
<_Fp
>::value
, 2>::type _Index
;
231 _VSTD::__thread_execute(*__p
.get(), _Index());
235 template <class _Fp
, class ..._Args
,
238 thread::thread(_Fp
&& __f
, _Args
&&... __args
)
240 typedef unique_ptr
<__thread_struct
> _TSPtr
;
241 _TSPtr
__tsp(new __thread_struct
);
242 typedef tuple
<_TSPtr
, __decay_t
<_Fp
>, __decay_t
<_Args
>...> _Gp
;
244 new _Gp(_VSTD::move(__tsp
),
245 _VSTD::forward
<_Fp
>(__f
),
246 _VSTD::forward
<_Args
>(__args
)...));
247 int __ec
= _VSTD::__libcpp_thread_create(&__t_
, &__thread_proxy
<_Gp
>, __p
.get());
251 __throw_system_error(__ec
, "thread constructor failed");
254 #else // _LIBCPP_CXX03_LANG
257 struct __thread_invoke_pair
{
258 // This type is used to pass memory for thread local storage and a functor
259 // to a newly created thread because std::pair doesn't work with
260 // std::unique_ptr in C++03.
261 _LIBCPP_HIDE_FROM_ABI
__thread_invoke_pair(_Fp
& __f
) : __tsp_(new __thread_struct
), __fn_(__f
) {}
262 unique_ptr
<__thread_struct
> __tsp_
;
267 _LIBCPP_HIDE_FROM_ABI
void* __thread_proxy_cxx03(void* __vp
)
269 unique_ptr
<_Fp
> __p(static_cast<_Fp
*>(__vp
));
270 __thread_local_data().set_pointer(__p
->__tsp_
.release());
276 thread::thread(_Fp __f
)
279 typedef __thread_invoke_pair
<_Fp
> _InvokePair
;
280 typedef unique_ptr
<_InvokePair
> _PairPtr
;
281 _PairPtr
__pp(new _InvokePair(__f
));
282 int __ec
= _VSTD::__libcpp_thread_create(&__t_
, &__thread_proxy_cxx03
<_InvokePair
>, __pp
.get());
286 __throw_system_error(__ec
, "thread constructor failed");
289 #endif // _LIBCPP_CXX03_LANG
291 inline _LIBCPP_INLINE_VISIBILITY
292 void swap(thread
& __x
, thread
& __y
) _NOEXCEPT
{__x
.swap(__y
);}
294 _LIBCPP_END_NAMESPACE_STD
296 #endif // _LIBCPP___THREAD_THREAD_H