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