xref: /llvm-project/libcxx/include/__cxx03/__thread/thread.h (revision ce7771902dc50d900de639d499a60486b83f70e0)
1e78f53d1SNikolas Klauser // -*- C++ -*-
2e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
3e78f53d1SNikolas Klauser //
4e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
6e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e78f53d1SNikolas Klauser //
8e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
9e78f53d1SNikolas Klauser 
10*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___THREAD_THREAD_H
11*ce777190SNikolas Klauser #define _LIBCPP___CXX03___THREAD_THREAD_H
12e78f53d1SNikolas Klauser 
1373fbae83SNikolas Klauser #include <__cxx03/__condition_variable/condition_variable.h>
1473fbae83SNikolas Klauser #include <__cxx03/__config>
1573fbae83SNikolas Klauser #include <__cxx03/__exception/terminate.h>
1673fbae83SNikolas Klauser #include <__cxx03/__functional/hash.h>
1773fbae83SNikolas Klauser #include <__cxx03/__functional/unary_function.h>
1873fbae83SNikolas Klauser #include <__cxx03/__memory/unique_ptr.h>
1973fbae83SNikolas Klauser #include <__cxx03/__mutex/mutex.h>
2073fbae83SNikolas Klauser #include <__cxx03/__system_error/system_error.h>
2173fbae83SNikolas Klauser #include <__cxx03/__thread/id.h>
2273fbae83SNikolas Klauser #include <__cxx03/__thread/support.h>
2373fbae83SNikolas Klauser #include <__cxx03/__utility/forward.h>
2473fbae83SNikolas Klauser #include <__cxx03/tuple>
25e78f53d1SNikolas Klauser 
26e78f53d1SNikolas Klauser #ifndef _LIBCPP_HAS_NO_LOCALIZATION
2773fbae83SNikolas Klauser #  include <__cxx03/locale>
2873fbae83SNikolas Klauser #  include <__cxx03/sstream>
29e78f53d1SNikolas Klauser #endif
30e78f53d1SNikolas Klauser 
31e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
32e78f53d1SNikolas Klauser #  pragma GCC system_header
33e78f53d1SNikolas Klauser #endif
34e78f53d1SNikolas Klauser 
35e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS
3673fbae83SNikolas Klauser #include <__cxx03/__undef_macros>
37e78f53d1SNikolas Klauser 
38e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD
39e78f53d1SNikolas Klauser 
40e78f53d1SNikolas Klauser template <class _Tp>
41e78f53d1SNikolas Klauser class __thread_specific_ptr;
42e78f53d1SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI __thread_struct;
43e78f53d1SNikolas Klauser class _LIBCPP_HIDDEN __thread_struct_imp;
44e78f53d1SNikolas Klauser class __assoc_sub_state;
45e78f53d1SNikolas Klauser 
46e78f53d1SNikolas Klauser _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
47e78f53d1SNikolas Klauser 
48e78f53d1SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI __thread_struct {
49e78f53d1SNikolas Klauser   __thread_struct_imp* __p_;
50e78f53d1SNikolas Klauser 
51e78f53d1SNikolas Klauser   __thread_struct(const __thread_struct&);
52e78f53d1SNikolas Klauser   __thread_struct& operator=(const __thread_struct&);
53e78f53d1SNikolas Klauser 
54e78f53d1SNikolas Klauser public:
55e78f53d1SNikolas Klauser   __thread_struct();
56e78f53d1SNikolas Klauser   ~__thread_struct();
57e78f53d1SNikolas Klauser 
58e78f53d1SNikolas Klauser   void notify_all_at_thread_exit(condition_variable*, mutex*);
59e78f53d1SNikolas Klauser   void __make_ready_at_thread_exit(__assoc_sub_state*);
60e78f53d1SNikolas Klauser };
61e78f53d1SNikolas Klauser 
62e78f53d1SNikolas Klauser template <class _Tp>
63e78f53d1SNikolas Klauser class __thread_specific_ptr {
64e78f53d1SNikolas Klauser   __libcpp_tls_key __key_;
65e78f53d1SNikolas Klauser 
66e78f53d1SNikolas Klauser   // Only __thread_local_data() may construct a __thread_specific_ptr
67e78f53d1SNikolas Klauser   // and only with _Tp == __thread_struct.
68e78f53d1SNikolas Klauser   static_assert(is_same<_Tp, __thread_struct>::value, "");
69e78f53d1SNikolas Klauser   __thread_specific_ptr();
70e78f53d1SNikolas Klauser   friend _LIBCPP_EXPORTED_FROM_ABI __thread_specific_ptr<__thread_struct>& __thread_local_data();
71e78f53d1SNikolas Klauser 
72e78f53d1SNikolas Klauser   _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
73e78f53d1SNikolas Klauser 
74e78f53d1SNikolas Klauser public:
75e78f53d1SNikolas Klauser   typedef _Tp* pointer;
76e78f53d1SNikolas Klauser 
77e78f53d1SNikolas Klauser   __thread_specific_ptr(const __thread_specific_ptr&)            = delete;
78e78f53d1SNikolas Klauser   __thread_specific_ptr& operator=(const __thread_specific_ptr&) = delete;
79e78f53d1SNikolas Klauser   ~__thread_specific_ptr();
80e78f53d1SNikolas Klauser 
81e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI pointer get() const { return static_cast<_Tp*>(__libcpp_tls_get(__key_)); }
82e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI pointer operator*() const { return *get(); }
83e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return get(); }
84e78f53d1SNikolas Klauser   void set_pointer(pointer __p);
85e78f53d1SNikolas Klauser };
86e78f53d1SNikolas Klauser 
87e78f53d1SNikolas Klauser template <class _Tp>
88e78f53d1SNikolas Klauser void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) {
89e78f53d1SNikolas Klauser   delete static_cast<pointer>(__p);
90e78f53d1SNikolas Klauser }
91e78f53d1SNikolas Klauser 
92e78f53d1SNikolas Klauser template <class _Tp>
93e78f53d1SNikolas Klauser __thread_specific_ptr<_Tp>::__thread_specific_ptr() {
94e78f53d1SNikolas Klauser   int __ec = __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
95e78f53d1SNikolas Klauser   if (__ec)
96e78f53d1SNikolas Klauser     __throw_system_error(__ec, "__thread_specific_ptr construction failed");
97e78f53d1SNikolas Klauser }
98e78f53d1SNikolas Klauser 
99e78f53d1SNikolas Klauser template <class _Tp>
100e78f53d1SNikolas Klauser __thread_specific_ptr<_Tp>::~__thread_specific_ptr() {
101e78f53d1SNikolas Klauser   // __thread_specific_ptr is only created with a static storage duration
102e78f53d1SNikolas Klauser   // so this destructor is only invoked during program termination. Invoking
103e78f53d1SNikolas Klauser   // pthread_key_delete(__key_) may prevent other threads from deleting their
104e78f53d1SNikolas Klauser   // thread local data. For this reason we leak the key.
105e78f53d1SNikolas Klauser }
106e78f53d1SNikolas Klauser 
107e78f53d1SNikolas Klauser template <class _Tp>
108e78f53d1SNikolas Klauser void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
109e78f53d1SNikolas Klauser   _LIBCPP_ASSERT_INTERNAL(get() == nullptr, "Attempting to overwrite thread local data");
110e78f53d1SNikolas Klauser   std::__libcpp_tls_set(__key_, __p);
111e78f53d1SNikolas Klauser }
112e78f53d1SNikolas Klauser 
113e78f53d1SNikolas Klauser template <>
114e78f53d1SNikolas Klauser struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> {
115e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
116e78f53d1SNikolas Klauser     return hash<__libcpp_thread_id>()(__v.__id_);
117e78f53d1SNikolas Klauser   }
118e78f53d1SNikolas Klauser };
119e78f53d1SNikolas Klauser 
120e78f53d1SNikolas Klauser #ifndef _LIBCPP_HAS_NO_LOCALIZATION
121e78f53d1SNikolas Klauser template <class _CharT, class _Traits>
122e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
123e78f53d1SNikolas Klauser operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) {
124e78f53d1SNikolas Klauser   // [thread.thread.id]/9
125e78f53d1SNikolas Klauser   //   Effects: Inserts the text representation for charT of id into out.
126e78f53d1SNikolas Klauser   //
127e78f53d1SNikolas Klauser   // [thread.thread.id]/2
128e78f53d1SNikolas Klauser   //   The text representation for the character type charT of an
129e78f53d1SNikolas Klauser   //   object of type thread::id is an unspecified sequence of charT
130e78f53d1SNikolas Klauser   //   such that, for two objects of type thread::id x and y, if
131e78f53d1SNikolas Klauser   //   x == y is true, the thread::id objects have the same text
132e78f53d1SNikolas Klauser   //   representation, and if x != y is true, the thread::id objects
133e78f53d1SNikolas Klauser   //   have distinct text representations.
134e78f53d1SNikolas Klauser   //
135e78f53d1SNikolas Klauser   // Since various flags in the output stream can affect how the
136e78f53d1SNikolas Klauser   // thread id is represented (e.g. numpunct or showbase), we
137e78f53d1SNikolas Klauser   // use a temporary stream instead and just output the thread
138e78f53d1SNikolas Klauser   // id representation as a string.
139e78f53d1SNikolas Klauser 
140e78f53d1SNikolas Klauser   basic_ostringstream<_CharT, _Traits> __sstr;
141e78f53d1SNikolas Klauser   __sstr.imbue(locale::classic());
142e78f53d1SNikolas Klauser   __sstr << __id.__id_;
143e78f53d1SNikolas Klauser   return __os << __sstr.str();
144e78f53d1SNikolas Klauser }
145e78f53d1SNikolas Klauser #endif // _LIBCPP_HAS_NO_LOCALIZATION
146e78f53d1SNikolas Klauser 
147e78f53d1SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI thread {
148e78f53d1SNikolas Klauser   __libcpp_thread_t __t_;
149e78f53d1SNikolas Klauser 
150e78f53d1SNikolas Klauser   thread(const thread&);
151e78f53d1SNikolas Klauser   thread& operator=(const thread&);
152e78f53d1SNikolas Klauser 
153e78f53d1SNikolas Klauser public:
154e78f53d1SNikolas Klauser   typedef __thread_id id;
155e78f53d1SNikolas Klauser   typedef __libcpp_thread_t native_handle_type;
156e78f53d1SNikolas Klauser 
157e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {}
158e78f53d1SNikolas Klauser #ifndef _LIBCPP_CXX03_LANG
159e78f53d1SNikolas Klauser   template <class _Fp, class... _Args, __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value, int> = 0>
160e78f53d1SNikolas Klauser   _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS explicit thread(_Fp&& __f, _Args&&... __args);
161e78f53d1SNikolas Klauser #else // _LIBCPP_CXX03_LANG
162e78f53d1SNikolas Klauser   template <class _Fp>
163e78f53d1SNikolas Klauser   _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS explicit thread(_Fp __f);
164e78f53d1SNikolas Klauser #endif
165e78f53d1SNikolas Klauser   ~thread();
166e78f53d1SNikolas Klauser 
167e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) { __t.__t_ = _LIBCPP_NULL_THREAD; }
168e78f53d1SNikolas Klauser 
169e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI thread& operator=(thread&& __t) _NOEXCEPT {
170e78f53d1SNikolas Klauser     if (!__libcpp_thread_isnull(&__t_))
171e78f53d1SNikolas Klauser       terminate();
172e78f53d1SNikolas Klauser     __t_     = __t.__t_;
173e78f53d1SNikolas Klauser     __t.__t_ = _LIBCPP_NULL_THREAD;
174e78f53d1SNikolas Klauser     return *this;
175e78f53d1SNikolas Klauser   }
176e78f53d1SNikolas Klauser 
177e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void swap(thread& __t) _NOEXCEPT { std::swap(__t_, __t.__t_); }
178e78f53d1SNikolas Klauser 
179e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); }
180e78f53d1SNikolas Klauser   void join();
181e78f53d1SNikolas Klauser   void detach();
182e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); }
183e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; }
184e78f53d1SNikolas Klauser 
185e78f53d1SNikolas Klauser   static unsigned hardware_concurrency() _NOEXCEPT;
186e78f53d1SNikolas Klauser };
187e78f53d1SNikolas Klauser 
188e78f53d1SNikolas Klauser #ifndef _LIBCPP_CXX03_LANG
189e78f53d1SNikolas Klauser 
190e78f53d1SNikolas Klauser template <class _TSp, class _Fp, class... _Args, size_t... _Indices>
191e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI void __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) {
192e78f53d1SNikolas Klauser   std::__invoke(std::move(std::get<1>(__t)), std::move(std::get<_Indices>(__t))...);
193e78f53d1SNikolas Klauser }
194e78f53d1SNikolas Klauser 
195e78f53d1SNikolas Klauser template <class _Fp>
196e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI void* __thread_proxy(void* __vp) {
197e78f53d1SNikolas Klauser   // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...>
198e78f53d1SNikolas Klauser   unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
199e78f53d1SNikolas Klauser   __thread_local_data().set_pointer(std::get<0>(*__p.get()).release());
200e78f53d1SNikolas Klauser   typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
201e78f53d1SNikolas Klauser   std::__thread_execute(*__p.get(), _Index());
202e78f53d1SNikolas Klauser   return nullptr;
203e78f53d1SNikolas Klauser }
204e78f53d1SNikolas Klauser 
205e78f53d1SNikolas Klauser template <class _Fp, class... _Args, __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value, int> >
206e78f53d1SNikolas Klauser thread::thread(_Fp&& __f, _Args&&... __args) {
207e78f53d1SNikolas Klauser   typedef unique_ptr<__thread_struct> _TSPtr;
208e78f53d1SNikolas Klauser   _TSPtr __tsp(new __thread_struct);
209e78f53d1SNikolas Klauser   typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp;
210e78f53d1SNikolas Klauser   unique_ptr<_Gp> __p(new _Gp(std::move(__tsp), std::forward<_Fp>(__f), std::forward<_Args>(__args)...));
211e78f53d1SNikolas Klauser   int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
212e78f53d1SNikolas Klauser   if (__ec == 0)
213e78f53d1SNikolas Klauser     __p.release();
214e78f53d1SNikolas Klauser   else
215e78f53d1SNikolas Klauser     __throw_system_error(__ec, "thread constructor failed");
216e78f53d1SNikolas Klauser }
217e78f53d1SNikolas Klauser 
218e78f53d1SNikolas Klauser #else // _LIBCPP_CXX03_LANG
219e78f53d1SNikolas Klauser 
220e78f53d1SNikolas Klauser template <class _Fp>
221e78f53d1SNikolas Klauser struct __thread_invoke_pair {
222e78f53d1SNikolas Klauser   // This type is used to pass memory for thread local storage and a functor
223e78f53d1SNikolas Klauser   // to a newly created thread because std::pair doesn't work with
224e78f53d1SNikolas Klauser   // std::unique_ptr in C++03.
225e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {}
226e78f53d1SNikolas Klauser   unique_ptr<__thread_struct> __tsp_;
227e78f53d1SNikolas Klauser   _Fp __fn_;
228e78f53d1SNikolas Klauser };
229e78f53d1SNikolas Klauser 
230e78f53d1SNikolas Klauser template <class _Fp>
231e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp) {
232e78f53d1SNikolas Klauser   unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
233e78f53d1SNikolas Klauser   __thread_local_data().set_pointer(__p->__tsp_.release());
234e78f53d1SNikolas Klauser   (__p->__fn_)();
235e78f53d1SNikolas Klauser   return nullptr;
236e78f53d1SNikolas Klauser }
237e78f53d1SNikolas Klauser 
238e78f53d1SNikolas Klauser template <class _Fp>
239e78f53d1SNikolas Klauser thread::thread(_Fp __f) {
240e78f53d1SNikolas Klauser   typedef __thread_invoke_pair<_Fp> _InvokePair;
241e78f53d1SNikolas Klauser   typedef unique_ptr<_InvokePair> _PairPtr;
242e78f53d1SNikolas Klauser   _PairPtr __pp(new _InvokePair(__f));
243e78f53d1SNikolas Klauser   int __ec = std::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get());
244e78f53d1SNikolas Klauser   if (__ec == 0)
245e78f53d1SNikolas Klauser     __pp.release();
246e78f53d1SNikolas Klauser   else
247e78f53d1SNikolas Klauser     __throw_system_error(__ec, "thread constructor failed");
248e78f53d1SNikolas Klauser }
249e78f53d1SNikolas Klauser 
250e78f53d1SNikolas Klauser #endif // _LIBCPP_CXX03_LANG
251e78f53d1SNikolas Klauser 
252e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI void swap(thread& __x, thread& __y) _NOEXCEPT { __x.swap(__y); }
253e78f53d1SNikolas Klauser 
254e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD
255e78f53d1SNikolas Klauser 
256e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS
257e78f53d1SNikolas Klauser 
258*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___THREAD_THREAD_H
259