1 | // -*- C++ -*- |
2 | //===--------------------------- thread -----------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP_THREAD |
11 | #define _LIBCPP_THREAD |
12 | |
13 | /* |
14 | |
15 | thread synopsis |
16 | |
17 | namespace std |
18 | { |
19 | |
20 | class thread |
21 | { |
22 | public: |
23 | class id; |
24 | typedef pthread_t native_handle_type; |
25 | |
26 | thread() noexcept; |
27 | template <class F, class ...Args> explicit thread(F&& f, Args&&... args); |
28 | ~thread(); |
29 | |
30 | thread(const thread&) = delete; |
31 | thread(thread&& t) noexcept; |
32 | |
33 | thread& operator=(const thread&) = delete; |
34 | thread& operator=(thread&& t) noexcept; |
35 | |
36 | void swap(thread& t) noexcept; |
37 | |
38 | bool joinable() const noexcept; |
39 | void join(); |
40 | void detach(); |
41 | id get_id() const noexcept; |
42 | native_handle_type native_handle(); |
43 | |
44 | static unsigned hardware_concurrency() noexcept; |
45 | }; |
46 | |
47 | void swap(thread& x, thread& y) noexcept; |
48 | |
49 | class thread::id |
50 | { |
51 | public: |
52 | id() noexcept; |
53 | }; |
54 | |
55 | bool operator==(thread::id x, thread::id y) noexcept; |
56 | bool operator!=(thread::id x, thread::id y) noexcept; |
57 | bool operator< (thread::id x, thread::id y) noexcept; |
58 | bool operator<=(thread::id x, thread::id y) noexcept; |
59 | bool operator> (thread::id x, thread::id y) noexcept; |
60 | bool operator>=(thread::id x, thread::id y) noexcept; |
61 | |
62 | template<class charT, class traits> |
63 | basic_ostream<charT, traits>& |
64 | operator<<(basic_ostream<charT, traits>& out, thread::id id); |
65 | |
66 | namespace this_thread |
67 | { |
68 | |
69 | thread::id get_id() noexcept; |
70 | |
71 | void yield() noexcept; |
72 | |
73 | template <class Clock, class Duration> |
74 | void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); |
75 | |
76 | template <class Rep, class Period> |
77 | void sleep_for(const chrono::duration<Rep, Period>& rel_time); |
78 | |
79 | } // this_thread |
80 | |
81 | } // std |
82 | |
83 | */ |
84 | |
85 | #include <__config> |
86 | #include <iosfwd> |
87 | #include <__functional_base> |
88 | #include <type_traits> |
89 | #include <cstddef> |
90 | #include <functional> |
91 | #include <memory> |
92 | #include <system_error> |
93 | #include <chrono> |
94 | #include <__mutex_base> |
95 | #ifndef _LIBCPP_CXX03_LANG |
96 | #include <tuple> |
97 | #endif |
98 | #include <__threading_support> |
99 | #include <__debug> |
100 | |
101 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
102 | #pragma GCC system_header |
103 | #endif |
104 | |
105 | _LIBCPP_PUSH_MACROS |
106 | #include <__undef_macros> |
107 | |
108 | #ifdef _LIBCPP_HAS_NO_THREADS |
109 | #error <thread> is not supported on this single threaded system |
110 | #else // !_LIBCPP_HAS_NO_THREADS |
111 | |
112 | _LIBCPP_BEGIN_NAMESPACE_STD |
113 | |
114 | template <class _Tp> class __thread_specific_ptr; |
115 | class _LIBCPP_TYPE_VIS __thread_struct; |
116 | class _LIBCPP_HIDDEN __thread_struct_imp; |
117 | class __assoc_sub_state; |
118 | |
119 | _LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
120 | |
121 | class _LIBCPP_TYPE_VIS __thread_struct |
122 | { |
123 | __thread_struct_imp* __p_; |
124 | |
125 | __thread_struct(const __thread_struct&); |
126 | __thread_struct& operator=(const __thread_struct&); |
127 | public: |
128 | __thread_struct(); |
129 | ~__thread_struct(); |
130 | |
131 | void notify_all_at_thread_exit(condition_variable*, mutex*); |
132 | void __make_ready_at_thread_exit(__assoc_sub_state*); |
133 | }; |
134 | |
135 | template <class _Tp> |
136 | class __thread_specific_ptr |
137 | { |
138 | __libcpp_tls_key __key_; |
139 | |
140 | // Only __thread_local_data() may construct a __thread_specific_ptr |
141 | // and only with _Tp == __thread_struct. |
142 | static_assert((is_same<_Tp, __thread_struct>::value), "" ); |
143 | __thread_specific_ptr(); |
144 | friend _LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
145 | |
146 | __thread_specific_ptr(const __thread_specific_ptr&); |
147 | __thread_specific_ptr& operator=(const __thread_specific_ptr&); |
148 | |
149 | _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*); |
150 | |
151 | public: |
152 | typedef _Tp* pointer; |
153 | |
154 | ~__thread_specific_ptr(); |
155 | |
156 | _LIBCPP_INLINE_VISIBILITY |
157 | pointer get() const {return static_cast<_Tp*>(__libcpp_tls_get(__key_));} |
158 | _LIBCPP_INLINE_VISIBILITY |
159 | pointer operator*() const {return *get();} |
160 | _LIBCPP_INLINE_VISIBILITY |
161 | pointer operator->() const {return get();} |
162 | void set_pointer(pointer __p); |
163 | }; |
164 | |
165 | template <class _Tp> |
166 | void _LIBCPP_TLS_DESTRUCTOR_CC |
167 | __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) |
168 | { |
169 | delete static_cast<pointer>(__p); |
170 | } |
171 | |
172 | template <class _Tp> |
173 | __thread_specific_ptr<_Tp>::__thread_specific_ptr() |
174 | { |
175 | int __ec = |
176 | __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit); |
177 | if (__ec) |
178 | __throw_system_error(__ec, "__thread_specific_ptr construction failed" ); |
179 | } |
180 | |
181 | template <class _Tp> |
182 | __thread_specific_ptr<_Tp>::~__thread_specific_ptr() |
183 | { |
184 | // __thread_specific_ptr is only created with a static storage duration |
185 | // so this destructor is only invoked during program termination. Invoking |
186 | // pthread_key_delete(__key_) may prevent other threads from deleting their |
187 | // thread local data. For this reason we leak the key. |
188 | } |
189 | |
190 | template <class _Tp> |
191 | void |
192 | __thread_specific_ptr<_Tp>::set_pointer(pointer __p) |
193 | { |
194 | _LIBCPP_ASSERT(get() == nullptr, |
195 | "Attempting to overwrite thread local data" ); |
196 | __libcpp_tls_set(__key_, __p); |
197 | } |
198 | |
199 | template<> |
200 | struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> |
201 | : public unary_function<__thread_id, size_t> |
202 | { |
203 | _LIBCPP_INLINE_VISIBILITY |
204 | size_t operator()(__thread_id __v) const _NOEXCEPT |
205 | { |
206 | return hash<__libcpp_thread_id>()(__v.__id_); |
207 | } |
208 | }; |
209 | |
210 | template<class _CharT, class _Traits> |
211 | _LIBCPP_INLINE_VISIBILITY |
212 | basic_ostream<_CharT, _Traits>& |
213 | operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) |
214 | {return __os << __id.__id_;} |
215 | |
216 | class _LIBCPP_TYPE_VIS thread |
217 | { |
218 | __libcpp_thread_t __t_; |
219 | |
220 | thread(const thread&); |
221 | thread& operator=(const thread&); |
222 | public: |
223 | typedef __thread_id id; |
224 | typedef __libcpp_thread_t native_handle_type; |
225 | |
226 | _LIBCPP_INLINE_VISIBILITY |
227 | thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {} |
228 | #ifndef _LIBCPP_CXX03_LANG |
229 | template <class _Fp, class ..._Args, |
230 | class = typename enable_if |
231 | < |
232 | !is_same<typename __uncvref<_Fp>::type, thread>::value |
233 | >::type |
234 | > |
235 | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS |
236 | explicit thread(_Fp&& __f, _Args&&... __args); |
237 | #else // _LIBCPP_CXX03_LANG |
238 | template <class _Fp> |
239 | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS |
240 | explicit thread(_Fp __f); |
241 | #endif |
242 | ~thread(); |
243 | |
244 | #ifndef _LIBCPP_CXX03_LANG |
245 | _LIBCPP_INLINE_VISIBILITY |
246 | thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {__t.__t_ = _LIBCPP_NULL_THREAD;} |
247 | _LIBCPP_INLINE_VISIBILITY |
248 | thread& operator=(thread&& __t) _NOEXCEPT; |
249 | #endif // _LIBCPP_CXX03_LANG |
250 | |
251 | _LIBCPP_INLINE_VISIBILITY |
252 | void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);} |
253 | |
254 | _LIBCPP_INLINE_VISIBILITY |
255 | bool joinable() const _NOEXCEPT {return !__libcpp_thread_isnull(&__t_);} |
256 | void join(); |
257 | void detach(); |
258 | _LIBCPP_INLINE_VISIBILITY |
259 | id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);} |
260 | _LIBCPP_INLINE_VISIBILITY |
261 | native_handle_type native_handle() _NOEXCEPT {return __t_;} |
262 | |
263 | static unsigned hardware_concurrency() _NOEXCEPT; |
264 | }; |
265 | |
266 | #ifndef _LIBCPP_CXX03_LANG |
267 | |
268 | template <class _TSp, class _Fp, class ..._Args, size_t ..._Indices> |
269 | inline _LIBCPP_INLINE_VISIBILITY |
270 | void |
271 | __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) |
272 | { |
273 | __invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...); |
274 | } |
275 | |
276 | template <class _Fp> |
277 | _LIBCPP_INLINE_VISIBILITY |
278 | void* __thread_proxy(void* __vp) |
279 | { |
280 | // _Fp = std::tuple< unique_ptr<__thread_struct>, Functor, Args...> |
281 | std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
282 | __thread_local_data().set_pointer(_VSTD::get<0>(*__p).release()); |
283 | typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index; |
284 | __thread_execute(*__p, _Index()); |
285 | return nullptr; |
286 | } |
287 | |
288 | template <class _Fp, class ..._Args, |
289 | class |
290 | > |
291 | thread::thread(_Fp&& __f, _Args&&... __args) |
292 | { |
293 | typedef unique_ptr<__thread_struct> _TSPtr; |
294 | _TSPtr __tsp(new __thread_struct); |
295 | typedef tuple<_TSPtr, typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp; |
296 | _VSTD::unique_ptr<_Gp> __p( |
297 | new _Gp(std::move(__tsp), |
298 | __decay_copy(_VSTD::forward<_Fp>(__f)), |
299 | __decay_copy(_VSTD::forward<_Args>(__args))...)); |
300 | int __ec = __libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get()); |
301 | if (__ec == 0) |
302 | __p.release(); |
303 | else |
304 | __throw_system_error(__ec, "thread constructor failed" ); |
305 | } |
306 | |
307 | inline |
308 | thread& |
309 | thread::operator=(thread&& __t) _NOEXCEPT |
310 | { |
311 | if (!__libcpp_thread_isnull(&__t_)) |
312 | terminate(); |
313 | __t_ = __t.__t_; |
314 | __t.__t_ = _LIBCPP_NULL_THREAD; |
315 | return *this; |
316 | } |
317 | |
318 | #else // _LIBCPP_CXX03_LANG |
319 | |
320 | template <class _Fp> |
321 | struct __thread_invoke_pair { |
322 | // This type is used to pass memory for thread local storage and a functor |
323 | // to a newly created thread because std::pair doesn't work with |
324 | // std::unique_ptr in C++03. |
325 | __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {} |
326 | unique_ptr<__thread_struct> __tsp_; |
327 | _Fp __fn_; |
328 | }; |
329 | |
330 | template <class _Fp> |
331 | void* __thread_proxy_cxx03(void* __vp) |
332 | { |
333 | std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
334 | __thread_local_data().set_pointer(__p->__tsp_.release()); |
335 | (__p->__fn_)(); |
336 | return nullptr; |
337 | } |
338 | |
339 | template <class _Fp> |
340 | thread::thread(_Fp __f) |
341 | { |
342 | |
343 | typedef __thread_invoke_pair<_Fp> _InvokePair; |
344 | typedef std::unique_ptr<_InvokePair> _PairPtr; |
345 | _PairPtr __pp(new _InvokePair(__f)); |
346 | int __ec = __libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get()); |
347 | if (__ec == 0) |
348 | __pp.release(); |
349 | else |
350 | __throw_system_error(__ec, "thread constructor failed" ); |
351 | } |
352 | |
353 | #endif // _LIBCPP_CXX03_LANG |
354 | |
355 | inline _LIBCPP_INLINE_VISIBILITY |
356 | void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);} |
357 | |
358 | namespace this_thread |
359 | { |
360 | |
361 | _LIBCPP_FUNC_VIS void sleep_for(const chrono::nanoseconds& __ns); |
362 | |
363 | template <class _Rep, class _Period> |
364 | void |
365 | sleep_for(const chrono::duration<_Rep, _Period>& __d) |
366 | { |
367 | using namespace chrono; |
368 | if (__d > duration<_Rep, _Period>::zero()) |
369 | { |
370 | #if defined(_LIBCPP_COMPILER_GCC) && (__powerpc__ || __POWERPC__) |
371 | // GCC's long double const folding is incomplete for IBM128 long doubles. |
372 | _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); |
373 | #else |
374 | _LIBCPP_CONSTEXPR duration<long double> _Max = duration<long double>(ULLONG_MAX/1000000000ULL) ; |
375 | #endif |
376 | nanoseconds __ns; |
377 | if (__d < _Max) |
378 | { |
379 | __ns = duration_cast<nanoseconds>(__d); |
380 | if (__ns < __d) |
381 | ++__ns; |
382 | } |
383 | else |
384 | __ns = nanoseconds::max(); |
385 | sleep_for(__ns); |
386 | } |
387 | } |
388 | |
389 | template <class _Clock, class _Duration> |
390 | void |
391 | sleep_until(const chrono::time_point<_Clock, _Duration>& __t) |
392 | { |
393 | using namespace chrono; |
394 | mutex __mut; |
395 | condition_variable __cv; |
396 | unique_lock<mutex> __lk(__mut); |
397 | while (_Clock::now() < __t) |
398 | __cv.wait_until(__lk, __t); |
399 | } |
400 | |
401 | template <class _Duration> |
402 | inline _LIBCPP_INLINE_VISIBILITY |
403 | void |
404 | sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t) |
405 | { |
406 | using namespace chrono; |
407 | sleep_for(__t - steady_clock::now()); |
408 | } |
409 | |
410 | inline _LIBCPP_INLINE_VISIBILITY |
411 | void yield() _NOEXCEPT {__libcpp_thread_yield();} |
412 | |
413 | } // this_thread |
414 | |
415 | _LIBCPP_END_NAMESPACE_STD |
416 | |
417 | #endif // !_LIBCPP_HAS_NO_THREADS |
418 | |
419 | _LIBCPP_POP_MACROS |
420 | |
421 | #endif // _LIBCPP_THREAD |
422 | |