xref: /freebsd-src/contrib/llvm-project/libcxx/include/__thread/thread.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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