106c3fb27SDimitry Andric // -*- C++ -*- 206c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 306c3fb27SDimitry Andric // 406c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 506c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 606c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 706c3fb27SDimitry Andric // 806c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 906c3fb27SDimitry Andric 1006c3fb27SDimitry Andric #ifndef _LIBCPP___THREAD_THREAD_H 1106c3fb27SDimitry Andric #define _LIBCPP___THREAD_THREAD_H 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric #include <__condition_variable/condition_variable.h> 1406c3fb27SDimitry Andric #include <__config> 1506c3fb27SDimitry Andric #include <__exception/terminate.h> 1606c3fb27SDimitry Andric #include <__functional/hash.h> 1706c3fb27SDimitry Andric #include <__functional/unary_function.h> 1806c3fb27SDimitry Andric #include <__memory/unique_ptr.h> 1906c3fb27SDimitry Andric #include <__mutex/mutex.h> 2006c3fb27SDimitry Andric #include <__system_error/system_error.h> 2106c3fb27SDimitry Andric #include <__thread/id.h> 2206c3fb27SDimitry Andric #include <__threading_support> 2306c3fb27SDimitry Andric #include <__utility/forward.h> 2406c3fb27SDimitry Andric #include <tuple> 2506c3fb27SDimitry Andric 2606c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION 2706c3fb27SDimitry Andric # include <locale> 2806c3fb27SDimitry Andric # include <sstream> 2906c3fb27SDimitry Andric #endif 3006c3fb27SDimitry Andric 3106c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 3206c3fb27SDimitry Andric # pragma GCC system_header 3306c3fb27SDimitry Andric #endif 3406c3fb27SDimitry Andric 3506c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 3606c3fb27SDimitry Andric 3706c3fb27SDimitry Andric template <class _Tp> class __thread_specific_ptr; 3806c3fb27SDimitry Andric class _LIBCPP_EXPORTED_FROM_ABI __thread_struct; 3906c3fb27SDimitry Andric class _LIBCPP_HIDDEN __thread_struct_imp; 4006c3fb27SDimitry Andric class __assoc_sub_state; 4106c3fb27SDimitry Andric 4206c3fb27SDimitry Andric _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data(); 4306c3fb27SDimitry Andric 4406c3fb27SDimitry Andric class _LIBCPP_EXPORTED_FROM_ABI __thread_struct 4506c3fb27SDimitry Andric { 4606c3fb27SDimitry Andric __thread_struct_imp* __p_; 4706c3fb27SDimitry Andric 4806c3fb27SDimitry Andric __thread_struct(const __thread_struct&); 4906c3fb27SDimitry Andric __thread_struct& operator=(const __thread_struct&); 5006c3fb27SDimitry Andric public: 5106c3fb27SDimitry Andric __thread_struct(); 5206c3fb27SDimitry Andric ~__thread_struct(); 5306c3fb27SDimitry Andric 5406c3fb27SDimitry Andric void notify_all_at_thread_exit(condition_variable*, mutex*); 5506c3fb27SDimitry Andric void __make_ready_at_thread_exit(__assoc_sub_state*); 5606c3fb27SDimitry Andric }; 5706c3fb27SDimitry Andric 5806c3fb27SDimitry Andric template <class _Tp> 5906c3fb27SDimitry Andric class __thread_specific_ptr 6006c3fb27SDimitry Andric { 6106c3fb27SDimitry Andric __libcpp_tls_key __key_; 6206c3fb27SDimitry Andric 6306c3fb27SDimitry Andric // Only __thread_local_data() may construct a __thread_specific_ptr 6406c3fb27SDimitry Andric // and only with _Tp == __thread_struct. 6506c3fb27SDimitry Andric static_assert((is_same<_Tp, __thread_struct>::value), ""); 6606c3fb27SDimitry Andric __thread_specific_ptr(); 6706c3fb27SDimitry Andric friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data(); 6806c3fb27SDimitry Andric 6906c3fb27SDimitry Andric __thread_specific_ptr(const __thread_specific_ptr&); 7006c3fb27SDimitry Andric __thread_specific_ptr& operator=(const __thread_specific_ptr&); 7106c3fb27SDimitry Andric 7206c3fb27SDimitry Andric _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*); 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric public: 7506c3fb27SDimitry Andric typedef _Tp* pointer; 7606c3fb27SDimitry Andric 7706c3fb27SDimitry Andric ~__thread_specific_ptr(); 7806c3fb27SDimitry Andric 79*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 8006c3fb27SDimitry Andric pointer get() const {return static_cast<_Tp*>(__libcpp_tls_get(__key_));} 81*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 8206c3fb27SDimitry Andric pointer operator*() const {return *get();} 83*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 8406c3fb27SDimitry Andric pointer operator->() const {return get();} 8506c3fb27SDimitry Andric void set_pointer(pointer __p); 8606c3fb27SDimitry Andric }; 8706c3fb27SDimitry Andric 8806c3fb27SDimitry Andric template <class _Tp> 8906c3fb27SDimitry Andric void _LIBCPP_TLS_DESTRUCTOR_CC 9006c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) 9106c3fb27SDimitry Andric { 9206c3fb27SDimitry Andric delete static_cast<pointer>(__p); 9306c3fb27SDimitry Andric } 9406c3fb27SDimitry Andric 9506c3fb27SDimitry Andric template <class _Tp> 9606c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::__thread_specific_ptr() 9706c3fb27SDimitry Andric { 9806c3fb27SDimitry Andric int __ec = 9906c3fb27SDimitry Andric __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit); 10006c3fb27SDimitry Andric if (__ec) 10106c3fb27SDimitry Andric __throw_system_error(__ec, "__thread_specific_ptr construction failed"); 10206c3fb27SDimitry Andric } 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric template <class _Tp> 10506c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::~__thread_specific_ptr() 10606c3fb27SDimitry Andric { 10706c3fb27SDimitry Andric // __thread_specific_ptr is only created with a static storage duration 10806c3fb27SDimitry Andric // so this destructor is only invoked during program termination. Invoking 10906c3fb27SDimitry Andric // pthread_key_delete(__key_) may prevent other threads from deleting their 11006c3fb27SDimitry Andric // thread local data. For this reason we leak the key. 11106c3fb27SDimitry Andric } 11206c3fb27SDimitry Andric 11306c3fb27SDimitry Andric template <class _Tp> 11406c3fb27SDimitry Andric void 11506c3fb27SDimitry Andric __thread_specific_ptr<_Tp>::set_pointer(pointer __p) 11606c3fb27SDimitry Andric { 11706c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(get() == nullptr, 11806c3fb27SDimitry Andric "Attempting to overwrite thread local data"); 11906c3fb27SDimitry Andric std::__libcpp_tls_set(__key_, __p); 12006c3fb27SDimitry Andric } 12106c3fb27SDimitry Andric 12206c3fb27SDimitry Andric template<> 12306c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> 12406c3fb27SDimitry Andric : public __unary_function<__thread_id, size_t> 12506c3fb27SDimitry Andric { 126*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 12706c3fb27SDimitry Andric size_t operator()(__thread_id __v) const _NOEXCEPT 12806c3fb27SDimitry Andric { 12906c3fb27SDimitry Andric return hash<__libcpp_thread_id>()(__v.__id_); 13006c3fb27SDimitry Andric } 13106c3fb27SDimitry Andric }; 13206c3fb27SDimitry Andric 13306c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION 13406c3fb27SDimitry Andric template <class _CharT, class _Traits> 135*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 13606c3fb27SDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) { 13706c3fb27SDimitry Andric // [thread.thread.id]/9 13806c3fb27SDimitry Andric // Effects: Inserts the text representation for charT of id into out. 13906c3fb27SDimitry Andric // 14006c3fb27SDimitry Andric // [thread.thread.id]/2 14106c3fb27SDimitry Andric // The text representation for the character type charT of an 14206c3fb27SDimitry Andric // object of type thread::id is an unspecified sequence of charT 14306c3fb27SDimitry Andric // such that, for two objects of type thread::id x and y, if 14406c3fb27SDimitry Andric // x == y is true, the thread::id objects have the same text 14506c3fb27SDimitry Andric // representation, and if x != y is true, the thread::id objects 14606c3fb27SDimitry Andric // have distinct text representations. 14706c3fb27SDimitry Andric // 14806c3fb27SDimitry Andric // Since various flags in the output stream can affect how the 14906c3fb27SDimitry Andric // thread id is represented (e.g. numpunct or showbase), we 15006c3fb27SDimitry Andric // use a temporary stream instead and just output the thread 15106c3fb27SDimitry Andric // id representation as a string. 15206c3fb27SDimitry Andric 15306c3fb27SDimitry Andric basic_ostringstream<_CharT, _Traits> __sstr; 15406c3fb27SDimitry Andric __sstr.imbue(locale::classic()); 15506c3fb27SDimitry Andric __sstr << __id.__id_; 15606c3fb27SDimitry Andric return __os << __sstr.str(); 15706c3fb27SDimitry Andric } 15806c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_LOCALIZATION 15906c3fb27SDimitry Andric 16006c3fb27SDimitry Andric class _LIBCPP_EXPORTED_FROM_ABI thread 16106c3fb27SDimitry Andric { 16206c3fb27SDimitry Andric __libcpp_thread_t __t_; 16306c3fb27SDimitry Andric 16406c3fb27SDimitry Andric thread(const thread&); 16506c3fb27SDimitry Andric thread& operator=(const thread&); 16606c3fb27SDimitry Andric public: 16706c3fb27SDimitry Andric typedef __thread_id id; 16806c3fb27SDimitry Andric typedef __libcpp_thread_t native_handle_type; 16906c3fb27SDimitry Andric 170*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 17106c3fb27SDimitry Andric thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {} 17206c3fb27SDimitry Andric #ifndef _LIBCPP_CXX03_LANG 17306c3fb27SDimitry Andric template <class _Fp, class ..._Args, 17406c3fb27SDimitry Andric class = __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value> > 17506c3fb27SDimitry Andric _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 17606c3fb27SDimitry Andric explicit thread(_Fp&& __f, _Args&&... __args); 17706c3fb27SDimitry Andric #else // _LIBCPP_CXX03_LANG 17806c3fb27SDimitry Andric template <class _Fp> 17906c3fb27SDimitry Andric _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 18006c3fb27SDimitry Andric explicit thread(_Fp __f); 18106c3fb27SDimitry Andric #endif 18206c3fb27SDimitry Andric ~thread(); 18306c3fb27SDimitry Andric 184*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 18506c3fb27SDimitry Andric thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) { 18606c3fb27SDimitry Andric __t.__t_ = _LIBCPP_NULL_THREAD; 18706c3fb27SDimitry Andric } 18806c3fb27SDimitry Andric 189*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 19006c3fb27SDimitry Andric thread& operator=(thread&& __t) _NOEXCEPT { 19106c3fb27SDimitry Andric if (!__libcpp_thread_isnull(&__t_)) 19206c3fb27SDimitry Andric terminate(); 19306c3fb27SDimitry Andric __t_ = __t.__t_; 19406c3fb27SDimitry Andric __t.__t_ = _LIBCPP_NULL_THREAD; 19506c3fb27SDimitry Andric return *this; 19606c3fb27SDimitry Andric } 19706c3fb27SDimitry Andric 198*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 199*5f757f3fSDimitry Andric void swap(thread& __t) _NOEXCEPT {std::swap(__t_, __t.__t_);} 20006c3fb27SDimitry Andric 201*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 20206c3fb27SDimitry Andric bool joinable() const _NOEXCEPT {return !__libcpp_thread_isnull(&__t_);} 20306c3fb27SDimitry Andric void join(); 20406c3fb27SDimitry Andric void detach(); 205*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 20606c3fb27SDimitry Andric id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);} 207*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 20806c3fb27SDimitry Andric native_handle_type native_handle() _NOEXCEPT {return __t_;} 20906c3fb27SDimitry Andric 21006c3fb27SDimitry Andric static unsigned hardware_concurrency() _NOEXCEPT; 21106c3fb27SDimitry Andric }; 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric #ifndef _LIBCPP_CXX03_LANG 21406c3fb27SDimitry Andric 21506c3fb27SDimitry Andric template <class _TSp, class _Fp, class ..._Args, size_t ..._Indices> 216*5f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI 21706c3fb27SDimitry Andric void 21806c3fb27SDimitry Andric __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) 21906c3fb27SDimitry Andric { 220*5f757f3fSDimitry Andric std::__invoke(std::move(std::get<1>(__t)), std::move(std::get<_Indices>(__t))...); 22106c3fb27SDimitry Andric } 22206c3fb27SDimitry Andric 22306c3fb27SDimitry Andric template <class _Fp> 224*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 22506c3fb27SDimitry Andric void* __thread_proxy(void* __vp) 22606c3fb27SDimitry Andric { 22706c3fb27SDimitry Andric // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...> 22806c3fb27SDimitry Andric unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); 229*5f757f3fSDimitry Andric __thread_local_data().set_pointer(std::get<0>(*__p.get()).release()); 23006c3fb27SDimitry Andric typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index; 231*5f757f3fSDimitry Andric std::__thread_execute(*__p.get(), _Index()); 23206c3fb27SDimitry Andric return nullptr; 23306c3fb27SDimitry Andric } 23406c3fb27SDimitry Andric 23506c3fb27SDimitry Andric template <class _Fp, class ..._Args, 23606c3fb27SDimitry Andric class 23706c3fb27SDimitry Andric > 23806c3fb27SDimitry Andric thread::thread(_Fp&& __f, _Args&&... __args) 23906c3fb27SDimitry Andric { 24006c3fb27SDimitry Andric typedef unique_ptr<__thread_struct> _TSPtr; 24106c3fb27SDimitry Andric _TSPtr __tsp(new __thread_struct); 24206c3fb27SDimitry Andric typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp; 24306c3fb27SDimitry Andric unique_ptr<_Gp> __p( 244*5f757f3fSDimitry Andric new _Gp(std::move(__tsp), 245*5f757f3fSDimitry Andric std::forward<_Fp>(__f), 246*5f757f3fSDimitry Andric std::forward<_Args>(__args)...)); 247*5f757f3fSDimitry Andric int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get()); 24806c3fb27SDimitry Andric if (__ec == 0) 24906c3fb27SDimitry Andric __p.release(); 25006c3fb27SDimitry Andric else 25106c3fb27SDimitry Andric __throw_system_error(__ec, "thread constructor failed"); 25206c3fb27SDimitry Andric } 25306c3fb27SDimitry Andric 25406c3fb27SDimitry Andric #else // _LIBCPP_CXX03_LANG 25506c3fb27SDimitry Andric 25606c3fb27SDimitry Andric template <class _Fp> 25706c3fb27SDimitry Andric struct __thread_invoke_pair { 25806c3fb27SDimitry Andric // This type is used to pass memory for thread local storage and a functor 25906c3fb27SDimitry Andric // to a newly created thread because std::pair doesn't work with 26006c3fb27SDimitry Andric // std::unique_ptr in C++03. 26106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {} 26206c3fb27SDimitry Andric unique_ptr<__thread_struct> __tsp_; 26306c3fb27SDimitry Andric _Fp __fn_; 26406c3fb27SDimitry Andric }; 26506c3fb27SDimitry Andric 26606c3fb27SDimitry Andric template <class _Fp> 26706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp) 26806c3fb27SDimitry Andric { 26906c3fb27SDimitry Andric unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); 27006c3fb27SDimitry Andric __thread_local_data().set_pointer(__p->__tsp_.release()); 27106c3fb27SDimitry Andric (__p->__fn_)(); 27206c3fb27SDimitry Andric return nullptr; 27306c3fb27SDimitry Andric } 27406c3fb27SDimitry Andric 27506c3fb27SDimitry Andric template <class _Fp> 27606c3fb27SDimitry Andric thread::thread(_Fp __f) 27706c3fb27SDimitry Andric { 27806c3fb27SDimitry Andric 27906c3fb27SDimitry Andric typedef __thread_invoke_pair<_Fp> _InvokePair; 28006c3fb27SDimitry Andric typedef unique_ptr<_InvokePair> _PairPtr; 28106c3fb27SDimitry Andric _PairPtr __pp(new _InvokePair(__f)); 282*5f757f3fSDimitry Andric int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get()); 28306c3fb27SDimitry Andric if (__ec == 0) 28406c3fb27SDimitry Andric __pp.release(); 28506c3fb27SDimitry Andric else 28606c3fb27SDimitry Andric __throw_system_error(__ec, "thread constructor failed"); 28706c3fb27SDimitry Andric } 28806c3fb27SDimitry Andric 28906c3fb27SDimitry Andric #endif // _LIBCPP_CXX03_LANG 29006c3fb27SDimitry Andric 291*5f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI 29206c3fb27SDimitry Andric void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);} 29306c3fb27SDimitry Andric 29406c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD 29506c3fb27SDimitry Andric 29606c3fb27SDimitry Andric #endif // _LIBCPP___THREAD_THREAD_H 297