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