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