xref: /freebsd-src/contrib/llvm-project/libcxx/include/__thread/thread.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric // -*- C++ -*-
2*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
3*06c3fb27SDimitry Andric //
4*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*06c3fb27SDimitry Andric //
8*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
9*06c3fb27SDimitry Andric 
10*06c3fb27SDimitry Andric #ifndef _LIBCPP___THREAD_THREAD_H
11*06c3fb27SDimitry Andric #define _LIBCPP___THREAD_THREAD_H
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #include <__condition_variable/condition_variable.h>
14*06c3fb27SDimitry Andric #include <__config>
15*06c3fb27SDimitry Andric #include <__exception/terminate.h>
16*06c3fb27SDimitry Andric #include <__functional/hash.h>
17*06c3fb27SDimitry Andric #include <__functional/unary_function.h>
18*06c3fb27SDimitry Andric #include <__memory/unique_ptr.h>
19*06c3fb27SDimitry Andric #include <__mutex/mutex.h>
20*06c3fb27SDimitry Andric #include <__system_error/system_error.h>
21*06c3fb27SDimitry Andric #include <__thread/id.h>
22*06c3fb27SDimitry Andric #include <__threading_support>
23*06c3fb27SDimitry Andric #include <__utility/forward.h>
24*06c3fb27SDimitry Andric #include <iosfwd>
25*06c3fb27SDimitry Andric #include <tuple>
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION
28*06c3fb27SDimitry Andric #  include <locale>
29*06c3fb27SDimitry Andric #  include <sstream>
30*06c3fb27SDimitry Andric #endif
31*06c3fb27SDimitry Andric 
32*06c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
33*06c3fb27SDimitry Andric #  pragma GCC system_header
34*06c3fb27SDimitry Andric #endif
35*06c3fb27SDimitry Andric 
36*06c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
37*06c3fb27SDimitry Andric 
38*06c3fb27SDimitry Andric template <class _Tp> class __thread_specific_ptr;
39*06c3fb27SDimitry Andric class _LIBCPP_EXPORTED_FROM_ABI __thread_struct;
40*06c3fb27SDimitry Andric class _LIBCPP_HIDDEN __thread_struct_imp;
41*06c3fb27SDimitry Andric class __assoc_sub_state;
42*06c3fb27SDimitry Andric 
43*06c3fb27SDimitry Andric _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
44*06c3fb27SDimitry Andric 
45*06c3fb27SDimitry Andric class _LIBCPP_EXPORTED_FROM_ABI __thread_struct
46*06c3fb27SDimitry Andric {
47*06c3fb27SDimitry Andric     __thread_struct_imp* __p_;
48*06c3fb27SDimitry Andric 
49*06c3fb27SDimitry Andric     __thread_struct(const __thread_struct&);
50*06c3fb27SDimitry Andric     __thread_struct& operator=(const __thread_struct&);
51*06c3fb27SDimitry Andric public:
52*06c3fb27SDimitry Andric     __thread_struct();
53*06c3fb27SDimitry Andric     ~__thread_struct();
54*06c3fb27SDimitry Andric 
55*06c3fb27SDimitry Andric     void notify_all_at_thread_exit(condition_variable*, mutex*);
56*06c3fb27SDimitry Andric     void __make_ready_at_thread_exit(__assoc_sub_state*);
57*06c3fb27SDimitry Andric };
58*06c3fb27SDimitry Andric 
59*06c3fb27SDimitry Andric template <class _Tp>
60*06c3fb27SDimitry Andric class __thread_specific_ptr
61*06c3fb27SDimitry Andric {
62*06c3fb27SDimitry Andric     __libcpp_tls_key __key_;
63*06c3fb27SDimitry Andric 
64*06c3fb27SDimitry Andric      // Only __thread_local_data() may construct a __thread_specific_ptr
65*06c3fb27SDimitry Andric      // and only with _Tp == __thread_struct.
66*06c3fb27SDimitry Andric     static_assert((is_same<_Tp, __thread_struct>::value), "");
67*06c3fb27SDimitry Andric     __thread_specific_ptr();
68*06c3fb27SDimitry Andric     friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
69*06c3fb27SDimitry Andric 
70*06c3fb27SDimitry Andric     __thread_specific_ptr(const __thread_specific_ptr&);
71*06c3fb27SDimitry Andric     __thread_specific_ptr& operator=(const __thread_specific_ptr&);
72*06c3fb27SDimitry Andric 
73*06c3fb27SDimitry Andric     _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
74*06c3fb27SDimitry Andric 
75*06c3fb27SDimitry Andric public:
76*06c3fb27SDimitry Andric     typedef _Tp* pointer;
77*06c3fb27SDimitry Andric 
78*06c3fb27SDimitry Andric     ~__thread_specific_ptr();
79*06c3fb27SDimitry Andric 
80*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
81*06c3fb27SDimitry Andric     pointer get() const {return static_cast<_Tp*>(__libcpp_tls_get(__key_));}
82*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
83*06c3fb27SDimitry Andric     pointer operator*() const {return *get();}
84*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
85*06c3fb27SDimitry Andric     pointer operator->() const {return get();}
86*06c3fb27SDimitry Andric     void set_pointer(pointer __p);
87*06c3fb27SDimitry Andric };
88*06c3fb27SDimitry Andric 
89*06c3fb27SDimitry Andric template <class _Tp>
90*06c3fb27SDimitry Andric void _LIBCPP_TLS_DESTRUCTOR_CC
91*06c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
92*06c3fb27SDimitry Andric {
93*06c3fb27SDimitry Andric     delete static_cast<pointer>(__p);
94*06c3fb27SDimitry Andric }
95*06c3fb27SDimitry Andric 
96*06c3fb27SDimitry Andric template <class _Tp>
97*06c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::__thread_specific_ptr()
98*06c3fb27SDimitry Andric {
99*06c3fb27SDimitry Andric   int __ec =
100*06c3fb27SDimitry Andric       __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
101*06c3fb27SDimitry Andric   if (__ec)
102*06c3fb27SDimitry Andric     __throw_system_error(__ec, "__thread_specific_ptr construction failed");
103*06c3fb27SDimitry Andric }
104*06c3fb27SDimitry Andric 
105*06c3fb27SDimitry Andric template <class _Tp>
106*06c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::~__thread_specific_ptr()
107*06c3fb27SDimitry Andric {
108*06c3fb27SDimitry Andric     // __thread_specific_ptr is only created with a static storage duration
109*06c3fb27SDimitry Andric     // so this destructor is only invoked during program termination. Invoking
110*06c3fb27SDimitry Andric     // pthread_key_delete(__key_) may prevent other threads from deleting their
111*06c3fb27SDimitry Andric     // thread local data. For this reason we leak the key.
112*06c3fb27SDimitry Andric }
113*06c3fb27SDimitry Andric 
114*06c3fb27SDimitry Andric template <class _Tp>
115*06c3fb27SDimitry Andric void
116*06c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::set_pointer(pointer __p)
117*06c3fb27SDimitry Andric {
118*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(get() == nullptr,
119*06c3fb27SDimitry Andric                    "Attempting to overwrite thread local data");
120*06c3fb27SDimitry Andric     std::__libcpp_tls_set(__key_, __p);
121*06c3fb27SDimitry Andric }
122*06c3fb27SDimitry Andric 
123*06c3fb27SDimitry Andric template<>
124*06c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>
125*06c3fb27SDimitry Andric     : public __unary_function<__thread_id, size_t>
126*06c3fb27SDimitry Andric {
127*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
128*06c3fb27SDimitry Andric     size_t operator()(__thread_id __v) const _NOEXCEPT
129*06c3fb27SDimitry Andric     {
130*06c3fb27SDimitry Andric         return hash<__libcpp_thread_id>()(__v.__id_);
131*06c3fb27SDimitry Andric     }
132*06c3fb27SDimitry Andric };
133*06c3fb27SDimitry Andric 
134*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION
135*06c3fb27SDimitry Andric template <class _CharT, class _Traits>
136*06c3fb27SDimitry Andric _LIBCPP_INLINE_VISIBILITY basic_ostream<_CharT, _Traits>&
137*06c3fb27SDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {
138*06c3fb27SDimitry Andric     // [thread.thread.id]/9
139*06c3fb27SDimitry Andric     //   Effects: Inserts the text representation for charT of id into out.
140*06c3fb27SDimitry Andric     //
141*06c3fb27SDimitry Andric     // [thread.thread.id]/2
142*06c3fb27SDimitry Andric     //   The text representation for the character type charT of an
143*06c3fb27SDimitry Andric     //   object of type thread::id is an unspecified sequence of charT
144*06c3fb27SDimitry Andric     //   such that, for two objects of type thread::id x and y, if
145*06c3fb27SDimitry Andric     //   x == y is true, the thread::id objects have the same text
146*06c3fb27SDimitry Andric     //   representation, and if x != y is true, the thread::id objects
147*06c3fb27SDimitry Andric     //   have distinct text representations.
148*06c3fb27SDimitry Andric     //
149*06c3fb27SDimitry Andric     // Since various flags in the output stream can affect how the
150*06c3fb27SDimitry Andric     // thread id is represented (e.g. numpunct or showbase), we
151*06c3fb27SDimitry Andric     // use a temporary stream instead and just output the thread
152*06c3fb27SDimitry Andric     // id representation as a string.
153*06c3fb27SDimitry Andric 
154*06c3fb27SDimitry Andric     basic_ostringstream<_CharT, _Traits> __sstr;
155*06c3fb27SDimitry Andric     __sstr.imbue(locale::classic());
156*06c3fb27SDimitry Andric     __sstr << __id.__id_;
157*06c3fb27SDimitry Andric     return __os << __sstr.str();
158*06c3fb27SDimitry Andric }
159*06c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_LOCALIZATION
160*06c3fb27SDimitry Andric 
161*06c3fb27SDimitry Andric class _LIBCPP_EXPORTED_FROM_ABI thread
162*06c3fb27SDimitry Andric {
163*06c3fb27SDimitry Andric     __libcpp_thread_t __t_;
164*06c3fb27SDimitry Andric 
165*06c3fb27SDimitry Andric     thread(const thread&);
166*06c3fb27SDimitry Andric     thread& operator=(const thread&);
167*06c3fb27SDimitry Andric public:
168*06c3fb27SDimitry Andric     typedef __thread_id id;
169*06c3fb27SDimitry Andric     typedef __libcpp_thread_t native_handle_type;
170*06c3fb27SDimitry Andric 
171*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
172*06c3fb27SDimitry Andric     thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {}
173*06c3fb27SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
174*06c3fb27SDimitry Andric     template <class _Fp, class ..._Args,
175*06c3fb27SDimitry Andric               class = __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value> >
176*06c3fb27SDimitry Andric         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
177*06c3fb27SDimitry Andric         explicit thread(_Fp&& __f, _Args&&... __args);
178*06c3fb27SDimitry Andric #else  // _LIBCPP_CXX03_LANG
179*06c3fb27SDimitry Andric     template <class _Fp>
180*06c3fb27SDimitry Andric     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
181*06c3fb27SDimitry Andric     explicit thread(_Fp __f);
182*06c3fb27SDimitry Andric #endif
183*06c3fb27SDimitry Andric     ~thread();
184*06c3fb27SDimitry Andric 
185*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
186*06c3fb27SDimitry Andric     thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {
187*06c3fb27SDimitry Andric         __t.__t_ = _LIBCPP_NULL_THREAD;
188*06c3fb27SDimitry Andric     }
189*06c3fb27SDimitry Andric 
190*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
191*06c3fb27SDimitry Andric     thread& operator=(thread&& __t) _NOEXCEPT {
192*06c3fb27SDimitry Andric         if (!__libcpp_thread_isnull(&__t_))
193*06c3fb27SDimitry Andric             terminate();
194*06c3fb27SDimitry Andric         __t_ = __t.__t_;
195*06c3fb27SDimitry Andric         __t.__t_ = _LIBCPP_NULL_THREAD;
196*06c3fb27SDimitry Andric         return *this;
197*06c3fb27SDimitry Andric     }
198*06c3fb27SDimitry Andric 
199*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
200*06c3fb27SDimitry Andric     void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);}
201*06c3fb27SDimitry Andric 
202*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
203*06c3fb27SDimitry Andric     bool joinable() const _NOEXCEPT {return !__libcpp_thread_isnull(&__t_);}
204*06c3fb27SDimitry Andric     void join();
205*06c3fb27SDimitry Andric     void detach();
206*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
207*06c3fb27SDimitry Andric     id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);}
208*06c3fb27SDimitry Andric     _LIBCPP_INLINE_VISIBILITY
209*06c3fb27SDimitry Andric     native_handle_type native_handle() _NOEXCEPT {return __t_;}
210*06c3fb27SDimitry Andric 
211*06c3fb27SDimitry Andric     static unsigned hardware_concurrency() _NOEXCEPT;
212*06c3fb27SDimitry Andric };
213*06c3fb27SDimitry Andric 
214*06c3fb27SDimitry Andric #ifndef _LIBCPP_CXX03_LANG
215*06c3fb27SDimitry Andric 
216*06c3fb27SDimitry Andric template <class _TSp, class _Fp, class ..._Args, size_t ..._Indices>
217*06c3fb27SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
218*06c3fb27SDimitry Andric void
219*06c3fb27SDimitry Andric __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>)
220*06c3fb27SDimitry Andric {
221*06c3fb27SDimitry Andric     _VSTD::__invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
222*06c3fb27SDimitry Andric }
223*06c3fb27SDimitry Andric 
224*06c3fb27SDimitry Andric template <class _Fp>
225*06c3fb27SDimitry Andric _LIBCPP_INLINE_VISIBILITY
226*06c3fb27SDimitry Andric void* __thread_proxy(void* __vp)
227*06c3fb27SDimitry Andric {
228*06c3fb27SDimitry Andric     // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
229*06c3fb27SDimitry Andric     unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
230*06c3fb27SDimitry Andric     __thread_local_data().set_pointer(_VSTD::get<0>(*__p.get()).release());
231*06c3fb27SDimitry Andric     typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
232*06c3fb27SDimitry Andric     _VSTD::__thread_execute(*__p.get(), _Index());
233*06c3fb27SDimitry Andric     return nullptr;
234*06c3fb27SDimitry Andric }
235*06c3fb27SDimitry Andric 
236*06c3fb27SDimitry Andric template <class _Fp, class ..._Args,
237*06c3fb27SDimitry Andric           class
238*06c3fb27SDimitry Andric          >
239*06c3fb27SDimitry Andric thread::thread(_Fp&& __f, _Args&&... __args)
240*06c3fb27SDimitry Andric {
241*06c3fb27SDimitry Andric     typedef unique_ptr<__thread_struct> _TSPtr;
242*06c3fb27SDimitry Andric     _TSPtr __tsp(new __thread_struct);
243*06c3fb27SDimitry Andric     typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp;
244*06c3fb27SDimitry Andric     unique_ptr<_Gp> __p(
245*06c3fb27SDimitry Andric             new _Gp(_VSTD::move(__tsp),
246*06c3fb27SDimitry Andric                     _VSTD::forward<_Fp>(__f),
247*06c3fb27SDimitry Andric                     _VSTD::forward<_Args>(__args)...));
248*06c3fb27SDimitry Andric     int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
249*06c3fb27SDimitry Andric     if (__ec == 0)
250*06c3fb27SDimitry Andric         __p.release();
251*06c3fb27SDimitry Andric     else
252*06c3fb27SDimitry Andric         __throw_system_error(__ec, "thread constructor failed");
253*06c3fb27SDimitry Andric }
254*06c3fb27SDimitry Andric 
255*06c3fb27SDimitry Andric #else  // _LIBCPP_CXX03_LANG
256*06c3fb27SDimitry Andric 
257*06c3fb27SDimitry Andric template <class _Fp>
258*06c3fb27SDimitry Andric struct __thread_invoke_pair {
259*06c3fb27SDimitry Andric     // This type is used to pass memory for thread local storage and a functor
260*06c3fb27SDimitry Andric     // to a newly created thread because std::pair doesn't work with
261*06c3fb27SDimitry Andric     // std::unique_ptr in C++03.
262*06c3fb27SDimitry Andric     _LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {}
263*06c3fb27SDimitry Andric     unique_ptr<__thread_struct> __tsp_;
264*06c3fb27SDimitry Andric     _Fp __fn_;
265*06c3fb27SDimitry Andric };
266*06c3fb27SDimitry Andric 
267*06c3fb27SDimitry Andric template <class _Fp>
268*06c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp)
269*06c3fb27SDimitry Andric {
270*06c3fb27SDimitry Andric     unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
271*06c3fb27SDimitry Andric     __thread_local_data().set_pointer(__p->__tsp_.release());
272*06c3fb27SDimitry Andric     (__p->__fn_)();
273*06c3fb27SDimitry Andric     return nullptr;
274*06c3fb27SDimitry Andric }
275*06c3fb27SDimitry Andric 
276*06c3fb27SDimitry Andric template <class _Fp>
277*06c3fb27SDimitry Andric thread::thread(_Fp __f)
278*06c3fb27SDimitry Andric {
279*06c3fb27SDimitry Andric 
280*06c3fb27SDimitry Andric     typedef __thread_invoke_pair<_Fp> _InvokePair;
281*06c3fb27SDimitry Andric     typedef unique_ptr<_InvokePair> _PairPtr;
282*06c3fb27SDimitry Andric     _PairPtr __pp(new _InvokePair(__f));
283*06c3fb27SDimitry Andric     int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get());
284*06c3fb27SDimitry Andric     if (__ec == 0)
285*06c3fb27SDimitry Andric         __pp.release();
286*06c3fb27SDimitry Andric     else
287*06c3fb27SDimitry Andric         __throw_system_error(__ec, "thread constructor failed");
288*06c3fb27SDimitry Andric }
289*06c3fb27SDimitry Andric 
290*06c3fb27SDimitry Andric #endif // _LIBCPP_CXX03_LANG
291*06c3fb27SDimitry Andric 
292*06c3fb27SDimitry Andric inline _LIBCPP_INLINE_VISIBILITY
293*06c3fb27SDimitry Andric void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);}
294*06c3fb27SDimitry Andric 
295*06c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
296*06c3fb27SDimitry Andric 
297*06c3fb27SDimitry Andric #endif // _LIBCPP___THREAD_THREAD_H
298