xref: /llvm-project/libcxx/include/__thread/thread.h (revision dedc5159997ebd3573a2e6397ba9b08faeb1b015)
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