1cea42859SHui // -*- C++ -*- 2cea42859SHui //===----------------------------------------------------------------------===// 3cea42859SHui // 4cea42859SHui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5cea42859SHui // See https://llvm.org/LICENSE.txt for license information. 6cea42859SHui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7cea42859SHui // 8cea42859SHui //===----------------------------------------------------------------------===// 9cea42859SHui 10cea42859SHui #ifndef _LIBCPP___THREAD_THREAD_H 11cea42859SHui #define _LIBCPP___THREAD_THREAD_H 12cea42859SHui 136808e6c7SLouis Dionne #include <__assert> 14cea42859SHui #include <__condition_variable/condition_variable.h> 15cea42859SHui #include <__config> 16cea42859SHui #include <__exception/terminate.h> 17cea42859SHui #include <__functional/hash.h> 18cea42859SHui #include <__functional/unary_function.h> 19cea42859SHui #include <__memory/unique_ptr.h> 20cea42859SHui #include <__mutex/mutex.h> 21*dedc5159SNikolas Klauser #include <__system_error/throw_system_error.h> 22053d9e58SLouis Dionne #include <__thread/id.h> 237162fd75SLouis Dionne #include <__thread/support.h> 2409e3a360SLouis Dionne #include <__type_traits/decay.h> 25*dedc5159SNikolas Klauser #include <__type_traits/enable_if.h> 26*dedc5159SNikolas Klauser #include <__type_traits/is_same.h> 27*dedc5159SNikolas Klauser #include <__type_traits/remove_cvref.h> 28cea42859SHui #include <__utility/forward.h> 29cea42859SHui #include <tuple> 30cea42859SHui 31c6f3b7bcSNikolas Klauser #if _LIBCPP_HAS_LOCALIZATION 321c1edd1bSMark de Wever # include <locale> 33dd5c4da5SMark de Wever # include <sstream> 341c1edd1bSMark de Wever #endif 351c1edd1bSMark de Wever 36cea42859SHui #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 37cea42859SHui # pragma GCC system_header 38cea42859SHui #endif 39cea42859SHui 407b462251SLouis Dionne _LIBCPP_PUSH_MACROS 417b462251SLouis Dionne #include <__undef_macros> 427b462251SLouis Dionne 43cea42859SHui _LIBCPP_BEGIN_NAMESPACE_STD 44cea42859SHui 45c6f3b7bcSNikolas Klauser #if _LIBCPP_HAS_THREADS 4687d56c59SLouis Dionne 479783f28cSLouis Dionne template <class _Tp> 489783f28cSLouis Dionne class __thread_specific_ptr; 49cea42859SHui class _LIBCPP_EXPORTED_FROM_ABI __thread_struct; 50cea42859SHui class _LIBCPP_HIDDEN __thread_struct_imp; 51cea42859SHui class __assoc_sub_state; 52cea42859SHui 53cea42859SHui _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data(); 54cea42859SHui 559783f28cSLouis Dionne class _LIBCPP_EXPORTED_FROM_ABI __thread_struct { 56cea42859SHui __thread_struct_imp* __p_; 57cea42859SHui 58cea42859SHui __thread_struct(const __thread_struct&); 59cea42859SHui __thread_struct& operator=(const __thread_struct&); 609783f28cSLouis Dionne 61cea42859SHui public: 62cea42859SHui __thread_struct(); 63cea42859SHui ~__thread_struct(); 64cea42859SHui 65cea42859SHui void notify_all_at_thread_exit(condition_variable*, mutex*); 66cea42859SHui void __make_ready_at_thread_exit(__assoc_sub_state*); 67cea42859SHui }; 68cea42859SHui 69cea42859SHui template <class _Tp> 709783f28cSLouis Dionne class __thread_specific_ptr { 71cea42859SHui __libcpp_tls_key __key_; 72cea42859SHui 73cea42859SHui // Only __thread_local_data() may construct a __thread_specific_ptr 74cea42859SHui // and only with _Tp == __thread_struct. 756b4b29f8SNikolas Klauser static_assert(is_same<_Tp, __thread_struct>::value, ""); 76cea42859SHui __thread_specific_ptr(); 77cea42859SHui friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data(); 78cea42859SHui 79cea42859SHui _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*); 80cea42859SHui 81cea42859SHui public: 82cea42859SHui typedef _Tp* pointer; 83cea42859SHui 84bbe4a806SNikolas Klauser __thread_specific_ptr(const __thread_specific_ptr&) = delete; 85bbe4a806SNikolas Klauser __thread_specific_ptr& operator=(const __thread_specific_ptr&) = delete; 86cea42859SHui ~__thread_specific_ptr(); 87cea42859SHui 889783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI pointer get() const { return static_cast<_Tp*>(__libcpp_tls_get(__key_)); } 899783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI pointer operator*() const { return *get(); } 909783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return get(); } 91cea42859SHui void set_pointer(pointer __p); 92cea42859SHui }; 93cea42859SHui 94cea42859SHui template <class _Tp> 959783f28cSLouis Dionne void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) { 96cea42859SHui delete static_cast<pointer>(__p); 97cea42859SHui } 98cea42859SHui 99cea42859SHui template <class _Tp> 1009783f28cSLouis Dionne __thread_specific_ptr<_Tp>::__thread_specific_ptr() { 1019783f28cSLouis Dionne int __ec = __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit); 102cea42859SHui if (__ec) 103cea42859SHui __throw_system_error(__ec, "__thread_specific_ptr construction failed"); 104cea42859SHui } 105cea42859SHui 106cea42859SHui template <class _Tp> 1079783f28cSLouis Dionne __thread_specific_ptr<_Tp>::~__thread_specific_ptr() { 108cea42859SHui // __thread_specific_ptr is only created with a static storage duration 109cea42859SHui // so this destructor is only invoked during program termination. Invoking 110cea42859SHui // pthread_key_delete(__key_) may prevent other threads from deleting their 111cea42859SHui // thread local data. For this reason we leak the key. 112cea42859SHui } 113cea42859SHui 114cea42859SHui template <class _Tp> 1159783f28cSLouis Dionne void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) { 1164f215fddSKonstantin Varlamov _LIBCPP_ASSERT_INTERNAL(get() == nullptr, "Attempting to overwrite thread local data"); 117cea42859SHui std::__libcpp_tls_set(__key_, __p); 118cea42859SHui } 119cea42859SHui 120cea42859SHui template <> 1219783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> { 1229783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT { 123cea42859SHui return hash<__libcpp_thread_id>()(__v.__id_); 124cea42859SHui } 125cea42859SHui }; 126cea42859SHui 127c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_LOCALIZATION 128cea42859SHui template <class _CharT, class _Traits> 1294c198542SLouis Dionne _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 1301c1edd1bSMark de Wever operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) { 1311c1edd1bSMark de Wever // [thread.thread.id]/9 1321c1edd1bSMark de Wever // Effects: Inserts the text representation for charT of id into out. 1331c1edd1bSMark de Wever // 1341c1edd1bSMark de Wever // [thread.thread.id]/2 1351c1edd1bSMark de Wever // The text representation for the character type charT of an 1361c1edd1bSMark de Wever // object of type thread::id is an unspecified sequence of charT 1371c1edd1bSMark de Wever // such that, for two objects of type thread::id x and y, if 1381c1edd1bSMark de Wever // x == y is true, the thread::id objects have the same text 1391c1edd1bSMark de Wever // representation, and if x != y is true, the thread::id objects 1401c1edd1bSMark de Wever // have distinct text representations. 1411c1edd1bSMark de Wever // 1421c1edd1bSMark de Wever // Since various flags in the output stream can affect how the 1431c1edd1bSMark de Wever // thread id is represented (e.g. numpunct or showbase), we 1441c1edd1bSMark de Wever // use a temporary stream instead and just output the thread 1451c1edd1bSMark de Wever // id representation as a string. 1461c1edd1bSMark de Wever 1471c1edd1bSMark de Wever basic_ostringstream<_CharT, _Traits> __sstr; 1481c1edd1bSMark de Wever __sstr.imbue(locale::classic()); 1491c1edd1bSMark de Wever __sstr << __id.__id_; 1501c1edd1bSMark de Wever return __os << __sstr.str(); 1511c1edd1bSMark de Wever } 152c6f3b7bcSNikolas Klauser # endif // _LIBCPP_HAS_LOCALIZATION 153cea42859SHui 1549783f28cSLouis Dionne class _LIBCPP_EXPORTED_FROM_ABI thread { 155cea42859SHui __libcpp_thread_t __t_; 156cea42859SHui 157cea42859SHui thread(const thread&); 158cea42859SHui thread& operator=(const thread&); 1599783f28cSLouis Dionne 160cea42859SHui public: 161cea42859SHui typedef __thread_id id; 162cea42859SHui typedef __libcpp_thread_t native_handle_type; 163cea42859SHui 1649783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {} 165cea42859SHui # ifndef _LIBCPP_CXX03_LANG 16676a24727SNikolas Klauser template <class _Fp, class... _Args, __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value, int> = 0> 1679783f28cSLouis Dionne _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS explicit thread(_Fp&& __f, _Args&&... __args); 168cea42859SHui # else // _LIBCPP_CXX03_LANG 169cea42859SHui template <class _Fp> 1709783f28cSLouis Dionne _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS explicit thread(_Fp __f); 171cea42859SHui # endif 172cea42859SHui ~thread(); 173cea42859SHui 1749783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) { __t.__t_ = _LIBCPP_NULL_THREAD; } 175cea42859SHui 1769783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI thread& operator=(thread&& __t) _NOEXCEPT { 177cea42859SHui if (!__libcpp_thread_isnull(&__t_)) 178cea42859SHui terminate(); 179cea42859SHui __t_ = __t.__t_; 180cea42859SHui __t.__t_ = _LIBCPP_NULL_THREAD; 181cea42859SHui return *this; 182cea42859SHui } 183cea42859SHui 1849783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI void swap(thread& __t) _NOEXCEPT { std::swap(__t_, __t.__t_); } 185cea42859SHui 1869783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); } 187cea42859SHui void join(); 188cea42859SHui void detach(); 1899783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); } 1909783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; } 191cea42859SHui 192cea42859SHui static unsigned hardware_concurrency() _NOEXCEPT; 193cea42859SHui }; 194cea42859SHui 195cea42859SHui # ifndef _LIBCPP_CXX03_LANG 196cea42859SHui 197cea42859SHui template <class _TSp, class _Fp, class... _Args, size_t... _Indices> 1989783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI void __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) { 19977a00c0dSLouis Dionne std::__invoke(std::move(std::get<1>(__t)), std::move(std::get<_Indices>(__t))...); 200cea42859SHui } 201cea42859SHui 202cea42859SHui template <class _Fp> 2039783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI void* __thread_proxy(void* __vp) { 204cea42859SHui // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...> 205cea42859SHui unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); 20677a00c0dSLouis Dionne __thread_local_data().set_pointer(std::get<0>(*__p.get()).release()); 207cea42859SHui typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index; 20877a00c0dSLouis Dionne std::__thread_execute(*__p.get(), _Index()); 209cea42859SHui return nullptr; 210cea42859SHui } 211cea42859SHui 21276a24727SNikolas Klauser template <class _Fp, class... _Args, __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value, int> > 2139783f28cSLouis Dionne thread::thread(_Fp&& __f, _Args&&... __args) { 214cea42859SHui typedef unique_ptr<__thread_struct> _TSPtr; 215cea42859SHui _TSPtr __tsp(new __thread_struct); 216cea42859SHui typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp; 2179783f28cSLouis Dionne unique_ptr<_Gp> __p(new _Gp(std::move(__tsp), std::forward<_Fp>(__f), std::forward<_Args>(__args)...)); 21877a00c0dSLouis Dionne int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get()); 219cea42859SHui if (__ec == 0) 220cea42859SHui __p.release(); 221cea42859SHui else 222cea42859SHui __throw_system_error(__ec, "thread constructor failed"); 223cea42859SHui } 224cea42859SHui 225cea42859SHui # else // _LIBCPP_CXX03_LANG 226cea42859SHui 227cea42859SHui template <class _Fp> 228cea42859SHui struct __thread_invoke_pair { 229cea42859SHui // This type is used to pass memory for thread local storage and a functor 230cea42859SHui // to a newly created thread because std::pair doesn't work with 231cea42859SHui // std::unique_ptr in C++03. 232cea42859SHui _LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {} 233cea42859SHui unique_ptr<__thread_struct> __tsp_; 234cea42859SHui _Fp __fn_; 235cea42859SHui }; 236cea42859SHui 237cea42859SHui template <class _Fp> 2389783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp) { 239cea42859SHui unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); 240cea42859SHui __thread_local_data().set_pointer(__p->__tsp_.release()); 241cea42859SHui (__p->__fn_)(); 242cea42859SHui return nullptr; 243cea42859SHui } 244cea42859SHui 245cea42859SHui template <class _Fp> 2469783f28cSLouis Dionne thread::thread(_Fp __f) { 247cea42859SHui typedef __thread_invoke_pair<_Fp> _InvokePair; 248cea42859SHui typedef unique_ptr<_InvokePair> _PairPtr; 249cea42859SHui _PairPtr __pp(new _InvokePair(__f)); 25077a00c0dSLouis Dionne int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get()); 251cea42859SHui if (__ec == 0) 252cea42859SHui __pp.release(); 253cea42859SHui else 254cea42859SHui __throw_system_error(__ec, "thread constructor failed"); 255cea42859SHui } 256cea42859SHui 257cea42859SHui # endif // _LIBCPP_CXX03_LANG 258cea42859SHui 2599783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI void swap(thread& __x, thread& __y) _NOEXCEPT { __x.swap(__y); } 260cea42859SHui 261c6f3b7bcSNikolas Klauser #endif // _LIBCPP_HAS_THREADS 26287d56c59SLouis Dionne 263cea42859SHui _LIBCPP_END_NAMESPACE_STD 264cea42859SHui 2657b462251SLouis Dionne _LIBCPP_POP_MACROS 2667b462251SLouis Dionne 267cea42859SHui #endif // _LIBCPP___THREAD_THREAD_H 268