/src/llvm-project-16.0.6.build/include/c++/v1/thread
Line | Count | Source (jump to first uncovered line) |
1 | | // -*- C++ -*- |
2 | | //===----------------------------------------------------------------------===// |
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; // removed in C++20 |
57 | | bool operator< (thread::id x, thread::id y) noexcept; // removed in C++20 |
58 | | bool operator<=(thread::id x, thread::id y) noexcept; // removed in C++20 |
59 | | bool operator> (thread::id x, thread::id y) noexcept; // removed in C++20 |
60 | | bool operator>=(thread::id x, thread::id y) noexcept; // removed in C++20 |
61 | | strong_ordering operator<=>(thread::id x, thread::id y) noexcept; // C++20 |
62 | | |
63 | | template<class charT, class traits> |
64 | | basic_ostream<charT, traits>& |
65 | | operator<<(basic_ostream<charT, traits>& out, thread::id id); |
66 | | |
67 | | namespace this_thread |
68 | | { |
69 | | |
70 | | thread::id get_id() noexcept; |
71 | | |
72 | | void yield() noexcept; |
73 | | |
74 | | template <class Clock, class Duration> |
75 | | void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); |
76 | | |
77 | | template <class Rep, class Period> |
78 | | void sleep_for(const chrono::duration<Rep, Period>& rel_time); |
79 | | |
80 | | } // this_thread |
81 | | |
82 | | } // std |
83 | | |
84 | | */ |
85 | | |
86 | | #include <__assert> // all public C++ headers provide the assertion handler |
87 | | #include <__config> |
88 | | #include <__functional/hash.h> |
89 | | #include <__memory/unique_ptr.h> |
90 | | #include <__mutex_base> |
91 | | #include <__thread/poll_with_backoff.h> |
92 | | #include <__thread/timed_backoff_policy.h> |
93 | | #include <__threading_support> |
94 | | #include <__utility/forward.h> |
95 | | #include <cstddef> |
96 | | #include <iosfwd> |
97 | | #include <system_error> |
98 | | #include <tuple> |
99 | | #include <type_traits> |
100 | | #include <version> |
101 | | |
102 | | // standard-mandated includes |
103 | | |
104 | | // [thread.syn] |
105 | | #include <compare> |
106 | | |
107 | | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
108 | | # pragma GCC system_header |
109 | | #endif |
110 | | |
111 | | _LIBCPP_PUSH_MACROS |
112 | | #include <__undef_macros> |
113 | | |
114 | | #ifdef _LIBCPP_HAS_NO_THREADS |
115 | | # error "<thread> is not supported since libc++ has been configured without support for threads." |
116 | | #endif |
117 | | |
118 | | _LIBCPP_BEGIN_NAMESPACE_STD |
119 | | |
120 | | template <class _Tp> class __thread_specific_ptr; |
121 | | class _LIBCPP_TYPE_VIS __thread_struct; |
122 | | class _LIBCPP_HIDDEN __thread_struct_imp; |
123 | | class __assoc_sub_state; |
124 | | |
125 | | _LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
126 | | |
127 | | class _LIBCPP_TYPE_VIS __thread_struct |
128 | | { |
129 | | __thread_struct_imp* __p_; |
130 | | |
131 | | __thread_struct(const __thread_struct&); |
132 | | __thread_struct& operator=(const __thread_struct&); |
133 | | public: |
134 | | __thread_struct(); |
135 | | ~__thread_struct(); |
136 | | |
137 | | void notify_all_at_thread_exit(condition_variable*, mutex*); |
138 | | void __make_ready_at_thread_exit(__assoc_sub_state*); |
139 | | }; |
140 | | |
141 | | template <class _Tp> |
142 | | class __thread_specific_ptr |
143 | | { |
144 | | __libcpp_tls_key __key_; |
145 | | |
146 | | // Only __thread_local_data() may construct a __thread_specific_ptr |
147 | | // and only with _Tp == __thread_struct. |
148 | | static_assert((is_same<_Tp, __thread_struct>::value), ""); |
149 | | __thread_specific_ptr(); |
150 | | friend _LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
151 | | |
152 | | __thread_specific_ptr(const __thread_specific_ptr&); |
153 | | __thread_specific_ptr& operator=(const __thread_specific_ptr&); |
154 | | |
155 | | _LIBCPP_HIDDEN static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*); |
156 | | |
157 | | public: |
158 | | typedef _Tp* pointer; |
159 | | |
160 | | ~__thread_specific_ptr(); |
161 | | |
162 | | _LIBCPP_INLINE_VISIBILITY |
163 | 0 | pointer get() const {return static_cast<_Tp*>(__libcpp_tls_get(__key_));} |
164 | | _LIBCPP_INLINE_VISIBILITY |
165 | | pointer operator*() const {return *get();} |
166 | | _LIBCPP_INLINE_VISIBILITY |
167 | 0 | pointer operator->() const {return get();} |
168 | | void set_pointer(pointer __p); |
169 | | }; |
170 | | |
171 | | template <class _Tp> |
172 | | void _LIBCPP_TLS_DESTRUCTOR_CC |
173 | | __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) |
174 | 0 | { |
175 | 0 | delete static_cast<pointer>(__p); |
176 | 0 | } |
177 | | |
178 | | template <class _Tp> |
179 | | __thread_specific_ptr<_Tp>::__thread_specific_ptr() |
180 | 0 | { |
181 | 0 | int __ec = |
182 | 0 | __libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit); |
183 | 0 | if (__ec) |
184 | 0 | __throw_system_error(__ec, "__thread_specific_ptr construction failed"); |
185 | 0 | } |
186 | | |
187 | | template <class _Tp> |
188 | | __thread_specific_ptr<_Tp>::~__thread_specific_ptr() |
189 | | { |
190 | | // __thread_specific_ptr is only created with a static storage duration |
191 | | // so this destructor is only invoked during program termination. Invoking |
192 | | // pthread_key_delete(__key_) may prevent other threads from deleting their |
193 | | // thread local data. For this reason we leak the key. |
194 | | } |
195 | | |
196 | | template <class _Tp> |
197 | | void |
198 | | __thread_specific_ptr<_Tp>::set_pointer(pointer __p) |
199 | 0 | { |
200 | 0 | _LIBCPP_ASSERT(get() == nullptr, |
201 | 0 | "Attempting to overwrite thread local data"); |
202 | 0 | std::__libcpp_tls_set(__key_, __p); |
203 | 0 | } |
204 | | |
205 | | template<> |
206 | | struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> |
207 | | : public __unary_function<__thread_id, size_t> |
208 | | { |
209 | | _LIBCPP_INLINE_VISIBILITY |
210 | | size_t operator()(__thread_id __v) const _NOEXCEPT |
211 | 0 | { |
212 | 0 | return hash<__libcpp_thread_id>()(__v.__id_); |
213 | 0 | } |
214 | | }; |
215 | | |
216 | | template<class _CharT, class _Traits> |
217 | | _LIBCPP_INLINE_VISIBILITY |
218 | | basic_ostream<_CharT, _Traits>& |
219 | | operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) |
220 | | {return __os << __id.__id_;} |
221 | | |
222 | | class _LIBCPP_TYPE_VIS thread |
223 | | { |
224 | | __libcpp_thread_t __t_; |
225 | | |
226 | | thread(const thread&); |
227 | | thread& operator=(const thread&); |
228 | | public: |
229 | | typedef __thread_id id; |
230 | | typedef __libcpp_thread_t native_handle_type; |
231 | | |
232 | | _LIBCPP_INLINE_VISIBILITY |
233 | 0 | thread() _NOEXCEPT : __t_(_LIBCPP_NULL_THREAD) {} |
234 | | #ifndef _LIBCPP_CXX03_LANG |
235 | | template <class _Fp, class ..._Args, |
236 | | class = __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value> > |
237 | | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS |
238 | | explicit thread(_Fp&& __f, _Args&&... __args); |
239 | | #else // _LIBCPP_CXX03_LANG |
240 | | template <class _Fp> |
241 | | _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS |
242 | | explicit thread(_Fp __f); |
243 | | #endif |
244 | | ~thread(); |
245 | | |
246 | | _LIBCPP_INLINE_VISIBILITY |
247 | 0 | thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) { |
248 | 0 | __t.__t_ = _LIBCPP_NULL_THREAD; |
249 | 0 | } |
250 | | |
251 | | _LIBCPP_INLINE_VISIBILITY |
252 | 0 | thread& operator=(thread&& __t) _NOEXCEPT { |
253 | 0 | if (!__libcpp_thread_isnull(&__t_)) |
254 | 0 | terminate(); |
255 | 0 | __t_ = __t.__t_; |
256 | 0 | __t.__t_ = _LIBCPP_NULL_THREAD; |
257 | 0 | return *this; |
258 | 0 | } |
259 | | |
260 | | _LIBCPP_INLINE_VISIBILITY |
261 | 0 | void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);} |
262 | | |
263 | | _LIBCPP_INLINE_VISIBILITY |
264 | 0 | bool joinable() const _NOEXCEPT {return !__libcpp_thread_isnull(&__t_);} |
265 | | void join(); |
266 | | void detach(); |
267 | | _LIBCPP_INLINE_VISIBILITY |
268 | 0 | id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);} |
269 | | _LIBCPP_INLINE_VISIBILITY |
270 | 0 | native_handle_type native_handle() _NOEXCEPT {return __t_;} |
271 | | |
272 | | static unsigned hardware_concurrency() _NOEXCEPT; |
273 | | }; |
274 | | |
275 | | #ifndef _LIBCPP_CXX03_LANG |
276 | | |
277 | | template <class _TSp, class _Fp, class ..._Args, size_t ..._Indices> |
278 | | inline _LIBCPP_INLINE_VISIBILITY |
279 | | void |
280 | | __thread_execute(tuple<_TSp, _Fp, _Args...>& __t, __tuple_indices<_Indices...>) |
281 | | { |
282 | | _VSTD::__invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...); |
283 | | } |
284 | | |
285 | | template <class _Fp> |
286 | | _LIBCPP_INLINE_VISIBILITY |
287 | | void* __thread_proxy(void* __vp) |
288 | | { |
289 | | // _Fp = tuple< unique_ptr<__thread_struct>, Functor, Args...> |
290 | | unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
291 | | __thread_local_data().set_pointer(_VSTD::get<0>(*__p.get()).release()); |
292 | | typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index; |
293 | | _VSTD::__thread_execute(*__p.get(), _Index()); |
294 | | return nullptr; |
295 | | } |
296 | | |
297 | | template <class _Fp, class ..._Args, |
298 | | class |
299 | | > |
300 | | thread::thread(_Fp&& __f, _Args&&... __args) |
301 | | { |
302 | | typedef unique_ptr<__thread_struct> _TSPtr; |
303 | | _TSPtr __tsp(new __thread_struct); |
304 | | typedef tuple<_TSPtr, typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp; |
305 | | unique_ptr<_Gp> __p( |
306 | | new _Gp(_VSTD::move(__tsp), |
307 | | _VSTD::forward<_Fp>(__f), |
308 | | _VSTD::forward<_Args>(__args)...)); |
309 | | int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get()); |
310 | | if (__ec == 0) |
311 | | __p.release(); |
312 | | else |
313 | | __throw_system_error(__ec, "thread constructor failed"); |
314 | | } |
315 | | |
316 | | #else // _LIBCPP_CXX03_LANG |
317 | | |
318 | | template <class _Fp> |
319 | | struct __thread_invoke_pair { |
320 | | // This type is used to pass memory for thread local storage and a functor |
321 | | // to a newly created thread because std::pair doesn't work with |
322 | | // std::unique_ptr in C++03. |
323 | | __thread_invoke_pair(_Fp& __f) : __tsp_(new __thread_struct), __fn_(__f) {} |
324 | | unique_ptr<__thread_struct> __tsp_; |
325 | | _Fp __fn_; |
326 | | }; |
327 | | |
328 | | template <class _Fp> |
329 | | _LIBCPP_HIDE_FROM_ABI void* __thread_proxy_cxx03(void* __vp) |
330 | | { |
331 | | unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
332 | | __thread_local_data().set_pointer(__p->__tsp_.release()); |
333 | | (__p->__fn_)(); |
334 | | return nullptr; |
335 | | } |
336 | | |
337 | | template <class _Fp> |
338 | | thread::thread(_Fp __f) |
339 | | { |
340 | | |
341 | | typedef __thread_invoke_pair<_Fp> _InvokePair; |
342 | | typedef unique_ptr<_InvokePair> _PairPtr; |
343 | | _PairPtr __pp(new _InvokePair(__f)); |
344 | | int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get()); |
345 | | if (__ec == 0) |
346 | | __pp.release(); |
347 | | else |
348 | | __throw_system_error(__ec, "thread constructor failed"); |
349 | | } |
350 | | |
351 | | #endif // _LIBCPP_CXX03_LANG |
352 | | |
353 | | inline _LIBCPP_INLINE_VISIBILITY |
354 | 0 | void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);} |
355 | | |
356 | | namespace this_thread |
357 | | { |
358 | | |
359 | | _LIBCPP_FUNC_VIS void sleep_for(const chrono::nanoseconds& __ns); |
360 | | |
361 | | template <class _Rep, class _Period> |
362 | | _LIBCPP_HIDE_FROM_ABI void |
363 | | sleep_for(const chrono::duration<_Rep, _Period>& __d) |
364 | | { |
365 | | if (__d > chrono::duration<_Rep, _Period>::zero()) |
366 | | { |
367 | | // The standard guarantees a 64bit signed integer resolution for nanoseconds, |
368 | | // so use INT64_MAX / 1e9 as cut-off point. Use a constant to avoid <climits> |
369 | | // and issues with long double folding on PowerPC with GCC. |
370 | | _LIBCPP_CONSTEXPR chrono::duration<long double> _Max = |
371 | | chrono::duration<long double>(9223372036.0L); |
372 | | chrono::nanoseconds __ns; |
373 | | if (__d < _Max) |
374 | | { |
375 | | __ns = chrono::duration_cast<chrono::nanoseconds>(__d); |
376 | | if (__ns < __d) |
377 | | ++__ns; |
378 | | } |
379 | | else |
380 | | __ns = chrono::nanoseconds::max(); |
381 | | this_thread::sleep_for(__ns); |
382 | | } |
383 | | } |
384 | | |
385 | | template <class _Clock, class _Duration> |
386 | | _LIBCPP_HIDE_FROM_ABI void |
387 | | sleep_until(const chrono::time_point<_Clock, _Duration>& __t) |
388 | | { |
389 | | mutex __mut; |
390 | | condition_variable __cv; |
391 | | unique_lock<mutex> __lk(__mut); |
392 | | while (_Clock::now() < __t) |
393 | | __cv.wait_until(__lk, __t); |
394 | | } |
395 | | |
396 | | template <class _Duration> |
397 | | inline _LIBCPP_INLINE_VISIBILITY |
398 | | void |
399 | | sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t) |
400 | | { |
401 | | this_thread::sleep_for(__t - chrono::steady_clock::now()); |
402 | | } |
403 | | |
404 | | inline _LIBCPP_INLINE_VISIBILITY |
405 | 0 | void yield() _NOEXCEPT {__libcpp_thread_yield();} |
406 | | |
407 | | } // namespace this_thread |
408 | | |
409 | | _LIBCPP_END_NAMESPACE_STD |
410 | | |
411 | | _LIBCPP_POP_MACROS |
412 | | |
413 | | #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 17 |
414 | | # include <chrono> |
415 | | #endif |
416 | | |
417 | | #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 |
418 | | # include <functional> |
419 | | #endif |
420 | | |
421 | | #endif // _LIBCPP_THREAD |