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