/Users/buildslave/jenkins/workspace/coverage/llvm-project/libcxx/include/__threading_support
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_THREADING_SUPPORT |
11 | | #define _LIBCPP_THREADING_SUPPORT |
12 | | |
13 | | #include <__config> |
14 | | #include <chrono> |
15 | | #include <iosfwd> |
16 | | #include <errno.h> |
17 | | |
18 | | #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER |
19 | | #pragma GCC system_header |
20 | | #endif |
21 | | |
22 | | #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) |
23 | | # include <__external_threading> |
24 | | #elif !defined(_LIBCPP_HAS_NO_THREADS) |
25 | | |
26 | | #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) |
27 | | # include <pthread.h> |
28 | | # include <sched.h> |
29 | | # ifdef __APPLE__ |
30 | | # define _LIBCPP_NO_NATIVE_SEMAPHORES |
31 | | # endif |
32 | | # ifndef _LIBCPP_NO_NATIVE_SEMAPHORES |
33 | | # include <semaphore.h> |
34 | | # endif |
35 | | #elif defined(_LIBCPP_HAS_THREAD_API_C11) |
36 | | # include <threads.h> |
37 | | #endif |
38 | | |
39 | | #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ |
40 | | defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL) || \ |
41 | | defined(_LIBCPP_HAS_THREAD_API_WIN32) |
42 | | #define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS |
43 | | #else |
44 | | #define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY |
45 | | #endif |
46 | | |
47 | | #if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(no_thread_safety_analysis) |
48 | | #define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis)) |
49 | | #else |
50 | | #define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
51 | | #endif |
52 | | |
53 | | typedef ::timespec __libcpp_timespec_t; |
54 | | #endif // !defined(_LIBCPP_HAS_NO_THREADS) |
55 | | |
56 | | _LIBCPP_PUSH_MACROS |
57 | | #include <__undef_macros> |
58 | | |
59 | | _LIBCPP_BEGIN_NAMESPACE_STD |
60 | | |
61 | | #if !defined(_LIBCPP_HAS_NO_THREADS) |
62 | | |
63 | | #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) |
64 | | // Mutex |
65 | | typedef pthread_mutex_t __libcpp_mutex_t; |
66 | | #define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER |
67 | | |
68 | | typedef pthread_mutex_t __libcpp_recursive_mutex_t; |
69 | | |
70 | | // Condition Variable |
71 | | typedef pthread_cond_t __libcpp_condvar_t; |
72 | | #define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER |
73 | | |
74 | | #ifndef _LIBCPP_NO_NATIVE_SEMAPHORES |
75 | | // Semaphore |
76 | | typedef sem_t __libcpp_semaphore_t; |
77 | | # define _LIBCPP_SEMAPHORE_MAX SEM_VALUE_MAX |
78 | | #endif |
79 | | |
80 | | // Execute once |
81 | | typedef pthread_once_t __libcpp_exec_once_flag; |
82 | | #define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT |
83 | | |
84 | | // Thread id |
85 | | typedef pthread_t __libcpp_thread_id; |
86 | | |
87 | | // Thread |
88 | 46 | #define _LIBCPP_NULL_THREAD 0U |
89 | | |
90 | | typedef pthread_t __libcpp_thread_t; |
91 | | |
92 | | // Thread Local Storage |
93 | | typedef pthread_key_t __libcpp_tls_key; |
94 | | |
95 | | #define _LIBCPP_TLS_DESTRUCTOR_CC |
96 | | #elif defined(_LIBCPP_HAS_THREAD_API_C11) |
97 | | // Mutex |
98 | | typedef mtx_t __libcpp_mutex_t; |
99 | | // mtx_t is a struct so using {} for initialization is valid. |
100 | | #define _LIBCPP_MUTEX_INITIALIZER {} |
101 | | |
102 | | typedef mtx_t __libcpp_recursive_mutex_t; |
103 | | |
104 | | // Condition Variable |
105 | | typedef cnd_t __libcpp_condvar_t; |
106 | | // cnd_t is a struct so using {} for initialization is valid. |
107 | | #define _LIBCPP_CONDVAR_INITIALIZER {} |
108 | | |
109 | | // Execute once |
110 | | typedef once_flag __libcpp_exec_once_flag; |
111 | | #define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT |
112 | | |
113 | | // Thread id |
114 | | typedef thrd_t __libcpp_thread_id; |
115 | | |
116 | | // Thread |
117 | | #define _LIBCPP_NULL_THREAD 0U |
118 | | |
119 | | typedef thrd_t __libcpp_thread_t; |
120 | | |
121 | | // Thread Local Storage |
122 | | typedef tss_t __libcpp_tls_key; |
123 | | |
124 | | #define _LIBCPP_TLS_DESTRUCTOR_CC |
125 | | #elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) |
126 | | // Mutex |
127 | | typedef void* __libcpp_mutex_t; |
128 | | #define _LIBCPP_MUTEX_INITIALIZER 0 |
129 | | |
130 | | #if defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__arm__) |
131 | | typedef void* __libcpp_recursive_mutex_t[6]; |
132 | | #elif defined(_M_AMD64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__) |
133 | | typedef void* __libcpp_recursive_mutex_t[5]; |
134 | | #else |
135 | | # error Unsupported architecture |
136 | | #endif |
137 | | |
138 | | // Condition Variable |
139 | | typedef void* __libcpp_condvar_t; |
140 | | #define _LIBCPP_CONDVAR_INITIALIZER 0 |
141 | | |
142 | | // Semaphore |
143 | | typedef void* __libcpp_semaphore_t; |
144 | | |
145 | | // Execute Once |
146 | | typedef void* __libcpp_exec_once_flag; |
147 | | #define _LIBCPP_EXEC_ONCE_INITIALIZER 0 |
148 | | |
149 | | // Thread ID |
150 | | typedef long __libcpp_thread_id; |
151 | | |
152 | | // Thread |
153 | | #define _LIBCPP_NULL_THREAD 0U |
154 | | |
155 | | typedef void* __libcpp_thread_t; |
156 | | |
157 | | // Thread Local Storage |
158 | | typedef long __libcpp_tls_key; |
159 | | |
160 | | #define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall |
161 | | #endif // !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) |
162 | | |
163 | | #if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) |
164 | | // Mutex |
165 | | _LIBCPP_THREAD_ABI_VISIBILITY |
166 | | int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m); |
167 | | |
168 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
169 | | int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m); |
170 | | |
171 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
172 | | bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m); |
173 | | |
174 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
175 | | int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m); |
176 | | |
177 | | _LIBCPP_THREAD_ABI_VISIBILITY |
178 | | int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m); |
179 | | |
180 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
181 | | int __libcpp_mutex_lock(__libcpp_mutex_t *__m); |
182 | | |
183 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
184 | | bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m); |
185 | | |
186 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
187 | | int __libcpp_mutex_unlock(__libcpp_mutex_t *__m); |
188 | | |
189 | | _LIBCPP_THREAD_ABI_VISIBILITY |
190 | | int __libcpp_mutex_destroy(__libcpp_mutex_t *__m); |
191 | | |
192 | | // Condition variable |
193 | | _LIBCPP_THREAD_ABI_VISIBILITY |
194 | | int __libcpp_condvar_signal(__libcpp_condvar_t* __cv); |
195 | | |
196 | | _LIBCPP_THREAD_ABI_VISIBILITY |
197 | | int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv); |
198 | | |
199 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
200 | | int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m); |
201 | | |
202 | | _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS |
203 | | int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, |
204 | | __libcpp_timespec_t *__ts); |
205 | | |
206 | | _LIBCPP_THREAD_ABI_VISIBILITY |
207 | | int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv); |
208 | | |
209 | | #ifndef _LIBCPP_NO_NATIVE_SEMAPHORES |
210 | | |
211 | | // Semaphore |
212 | | _LIBCPP_THREAD_ABI_VISIBILITY |
213 | | bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init); |
214 | | |
215 | | _LIBCPP_THREAD_ABI_VISIBILITY |
216 | | bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem); |
217 | | |
218 | | _LIBCPP_THREAD_ABI_VISIBILITY |
219 | | bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem); |
220 | | |
221 | | _LIBCPP_THREAD_ABI_VISIBILITY |
222 | | bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem); |
223 | | |
224 | | _LIBCPP_THREAD_ABI_VISIBILITY |
225 | | bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns); |
226 | | |
227 | | #endif // _LIBCPP_NO_NATIVE_SEMAPHORES |
228 | | |
229 | | // Execute once |
230 | | _LIBCPP_THREAD_ABI_VISIBILITY |
231 | | int __libcpp_execute_once(__libcpp_exec_once_flag *flag, |
232 | | void (*init_routine)()); |
233 | | |
234 | | // Thread id |
235 | | _LIBCPP_THREAD_ABI_VISIBILITY |
236 | | bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2); |
237 | | |
238 | | _LIBCPP_THREAD_ABI_VISIBILITY |
239 | | bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2); |
240 | | |
241 | | // Thread |
242 | | _LIBCPP_THREAD_ABI_VISIBILITY |
243 | | bool __libcpp_thread_isnull(const __libcpp_thread_t *__t); |
244 | | |
245 | | _LIBCPP_THREAD_ABI_VISIBILITY |
246 | | int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), |
247 | | void *__arg); |
248 | | |
249 | | _LIBCPP_THREAD_ABI_VISIBILITY |
250 | | __libcpp_thread_id __libcpp_thread_get_current_id(); |
251 | | |
252 | | _LIBCPP_THREAD_ABI_VISIBILITY |
253 | | __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t); |
254 | | |
255 | | _LIBCPP_THREAD_ABI_VISIBILITY |
256 | | int __libcpp_thread_join(__libcpp_thread_t *__t); |
257 | | |
258 | | _LIBCPP_THREAD_ABI_VISIBILITY |
259 | | int __libcpp_thread_detach(__libcpp_thread_t *__t); |
260 | | |
261 | | _LIBCPP_THREAD_ABI_VISIBILITY |
262 | | void __libcpp_thread_yield(); |
263 | | |
264 | | _LIBCPP_THREAD_ABI_VISIBILITY |
265 | | void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns); |
266 | | |
267 | | // Thread local storage |
268 | | _LIBCPP_THREAD_ABI_VISIBILITY |
269 | | int __libcpp_tls_create(__libcpp_tls_key* __key, |
270 | | void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*)); |
271 | | |
272 | | _LIBCPP_THREAD_ABI_VISIBILITY |
273 | | void *__libcpp_tls_get(__libcpp_tls_key __key); |
274 | | |
275 | | _LIBCPP_THREAD_ABI_VISIBILITY |
276 | | int __libcpp_tls_set(__libcpp_tls_key __key, void *__p); |
277 | | |
278 | | #endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) |
279 | | |
280 | | struct __libcpp_timed_backoff_policy { |
281 | | _LIBCPP_THREAD_ABI_VISIBILITY |
282 | | bool operator()(chrono::nanoseconds __elapsed) const; |
283 | | }; |
284 | | |
285 | | inline _LIBCPP_INLINE_VISIBILITY |
286 | | bool __libcpp_timed_backoff_policy::operator()(chrono::nanoseconds __elapsed) const |
287 | 0 | { |
288 | 0 | if(__elapsed > chrono::milliseconds(128)) |
289 | 0 | __libcpp_thread_sleep_for(chrono::milliseconds(8)); |
290 | 0 | else if(__elapsed > chrono::microseconds(64)) |
291 | 0 | __libcpp_thread_sleep_for(__elapsed / 2); |
292 | 0 | else if(__elapsed > chrono::microseconds(4)) |
293 | 0 | __libcpp_thread_yield(); |
294 | 0 | else |
295 | 0 | ; // poll |
296 | 0 | return false; |
297 | 0 | } |
298 | | |
299 | | static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64; |
300 | | |
301 | | template<class _Fn, class _BFn> |
302 | | _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY |
303 | | bool __libcpp_thread_poll_with_backoff( |
304 | | _Fn && __f, _BFn && __bf, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero()) |
305 | 0 | { |
306 | 0 | auto const __start = chrono::high_resolution_clock::now(); |
307 | 0 | for(int __count = 0;;) { |
308 | 0 | if(__f()) |
309 | 0 | return true; // _Fn completion means success |
310 | 0 | if(__count < __libcpp_polling_count) { |
311 | 0 | __count += 1; |
312 | 0 | continue; |
313 | 0 | } |
314 | 0 | chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start; |
315 | 0 | if(__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed) |
316 | 0 | return false; // timeout failure |
317 | 0 | if(__bf(__elapsed)) |
318 | 0 | return false; // _BFn completion means failure |
319 | 0 | } |
320 | 0 | } Unexecuted instantiation: bool std::__1::__libcpp_thread_poll_with_backoff<std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const volatile, bool>&, std::__1::__libcpp_atomic_wait_backoff_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const volatile, std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const volatile, bool> >&>(std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const volatile, bool>&, std::__1::__libcpp_atomic_wait_backoff_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const volatile, std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const volatile, bool> >&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> >) Unexecuted instantiation: bool std::__1::__libcpp_thread_poll_with_backoff<std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const, bool>&, std::__1::__libcpp_atomic_wait_backoff_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const, std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const, bool> >&>(std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const, bool>&, std::__1::__libcpp_atomic_wait_backoff_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const, std::__1::__cxx_atomic_wait_test_fn_impl<std::__1::__cxx_atomic_impl<bool, std::__1::__cxx_atomic_base_impl<bool> > const, bool> >&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> >) Unexecuted instantiation: atomic.cpp:bool std::__1::__libcpp_thread_poll_with_backoff<std::__1::__libcpp_platform_wait_on_address(std::__1::__cxx_atomic_impl<long long, std::__1::__cxx_atomic_base_impl<long long> > const volatile*, long long)::$_0, std::__1::__libcpp_timed_backoff_policy>(std::__1::__libcpp_platform_wait_on_address(std::__1::__cxx_atomic_impl<long long, std::__1::__cxx_atomic_base_impl<long long> > const volatile*, long long)::$_0&&, std::__1::__libcpp_timed_backoff_policy&&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> >) |
321 | | |
322 | | #if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ |
323 | | defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) |
324 | | |
325 | | |
326 | | namespace __thread_detail { |
327 | | |
328 | | inline __libcpp_timespec_t __convert_to_timespec(const chrono::nanoseconds& __ns) |
329 | 0 | { |
330 | 0 | using namespace chrono; |
331 | 0 | seconds __s = duration_cast<seconds>(__ns); |
332 | 0 | __libcpp_timespec_t __ts; |
333 | 0 | typedef decltype(__ts.tv_sec) __ts_sec; |
334 | 0 | const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); |
335 | 0 |
|
336 | 0 | if (__s.count() < __ts_sec_max) |
337 | 0 | { |
338 | 0 | __ts.tv_sec = static_cast<__ts_sec>(__s.count()); |
339 | 0 | __ts.tv_nsec = static_cast<decltype(__ts.tv_nsec)>((__ns - __s).count()); |
340 | 0 | } |
341 | 0 | else |
342 | 0 | { |
343 | 0 | __ts.tv_sec = __ts_sec_max; |
344 | 0 | __ts.tv_nsec = 999999999; // (10^9 - 1) |
345 | 0 | } |
346 | 0 |
|
347 | 0 | return __ts; |
348 | 0 | } |
349 | | |
350 | | } |
351 | | |
352 | | #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) |
353 | | |
354 | | int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) |
355 | 30.9k | { |
356 | 30.9k | pthread_mutexattr_t attr; |
357 | 30.9k | int __ec = pthread_mutexattr_init(&attr); |
358 | 30.9k | if (__ec) |
359 | 0 | return __ec; |
360 | 30.9k | __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); |
361 | 30.9k | if (__ec) { |
362 | 0 | pthread_mutexattr_destroy(&attr); |
363 | 0 | return __ec; |
364 | 0 | } |
365 | 30.9k | __ec = pthread_mutex_init(__m, &attr); |
366 | 30.9k | if (__ec) { |
367 | 0 | pthread_mutexattr_destroy(&attr); |
368 | 0 | return __ec; |
369 | 0 | } |
370 | 30.9k | __ec = pthread_mutexattr_destroy(&attr); |
371 | 30.9k | if (__ec) { |
372 | 0 | pthread_mutex_destroy(__m); |
373 | 0 | return __ec; |
374 | 0 | } |
375 | 30.9k | return 0; |
376 | 30.9k | } |
377 | | |
378 | | int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) |
379 | 112k | { |
380 | 112k | return pthread_mutex_lock(__m); |
381 | 112k | } |
382 | | |
383 | | bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) |
384 | 9 | { |
385 | 9 | return pthread_mutex_trylock(__m) == 0; |
386 | 9 | } |
387 | | |
388 | | int __libcpp_recursive_mutex_unlock(__libcpp_mutex_t *__m) |
389 | 112k | { |
390 | 112k | return pthread_mutex_unlock(__m); |
391 | 112k | } |
392 | | |
393 | | int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) |
394 | 6.73k | { |
395 | 6.73k | return pthread_mutex_destroy(__m); |
396 | 6.73k | } |
397 | | |
398 | | int __libcpp_mutex_lock(__libcpp_mutex_t *__m) |
399 | 731k | { |
400 | 731k | return pthread_mutex_lock(__m); |
401 | 731k | } |
402 | | |
403 | | bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) |
404 | 0 | { |
405 | 0 | return pthread_mutex_trylock(__m) == 0; |
406 | 0 | } |
407 | | |
408 | | int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) |
409 | 731k | { |
410 | 731k | return pthread_mutex_unlock(__m); |
411 | 731k | } |
412 | | |
413 | | int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) |
414 | 26.1k | { |
415 | 26.1k | return pthread_mutex_destroy(__m); |
416 | 26.1k | } |
417 | | |
418 | | // Condition Variable |
419 | | int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) |
420 | 117 | { |
421 | 117 | return pthread_cond_signal(__cv); |
422 | 117 | } |
423 | | |
424 | | int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) |
425 | 258k | { |
426 | 258k | return pthread_cond_broadcast(__cv); |
427 | 258k | } |
428 | | |
429 | | int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m) |
430 | 75 | { |
431 | 75 | return pthread_cond_wait(__cv, __m); |
432 | 75 | } |
433 | | |
434 | | int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, |
435 | | __libcpp_timespec_t *__ts) |
436 | 13 | { |
437 | 13 | return pthread_cond_timedwait(__cv, __m, __ts); |
438 | 13 | } |
439 | | |
440 | | int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) |
441 | 127 | { |
442 | 127 | return pthread_cond_destroy(__cv); |
443 | 127 | } |
444 | | |
445 | | #ifndef _LIBCPP_NO_NATIVE_SEMAPHORES |
446 | | |
447 | | // Semaphore |
448 | | bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init) |
449 | | { |
450 | | return sem_init(__sem, 0, __init) == 0; |
451 | | } |
452 | | |
453 | | bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem) |
454 | | { |
455 | | return sem_destroy(__sem) == 0; |
456 | | } |
457 | | |
458 | | bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem) |
459 | | { |
460 | | return sem_post(__sem) == 0; |
461 | | } |
462 | | |
463 | | bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem) |
464 | | { |
465 | | return sem_wait(__sem) == 0; |
466 | | } |
467 | | |
468 | | bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns) |
469 | | { |
470 | | auto const __abs_time = chrono::system_clock::now().time_since_epoch() + __ns; |
471 | | __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__abs_time); |
472 | | return sem_timedwait(__sem, &__ts) == 0; |
473 | | } |
474 | | |
475 | | #endif //_LIBCPP_NO_NATIVE_SEMAPHORES |
476 | | |
477 | | // Execute once |
478 | | int __libcpp_execute_once(__libcpp_exec_once_flag *flag, |
479 | 0 | void (*init_routine)()) { |
480 | 0 | return pthread_once(flag, init_routine); |
481 | 0 | } |
482 | | |
483 | | // Thread id |
484 | | // Returns non-zero if the thread ids are equal, otherwise 0 |
485 | | bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) |
486 | 32 | { |
487 | 32 | return pthread_equal(t1, t2) != 0; |
488 | 32 | } |
489 | | |
490 | | // Returns non-zero if t1 < t2, otherwise 0 |
491 | | bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) |
492 | 0 | { |
493 | 0 | return t1 < t2; |
494 | 0 | } |
495 | | |
496 | | // Thread |
497 | 99 | bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { |
498 | 99 | return *__t == 0; |
499 | 99 | } |
500 | | |
501 | | int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), |
502 | | void *__arg) |
503 | | { |
504 | | return pthread_create(__t, 0, __func, __arg); |
505 | | } |
506 | | |
507 | | __libcpp_thread_id __libcpp_thread_get_current_id() |
508 | 105k | { |
509 | 105k | return pthread_self(); |
510 | 105k | } |
511 | | |
512 | | __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) |
513 | | { |
514 | | return *__t; |
515 | | } |
516 | | |
517 | | int __libcpp_thread_join(__libcpp_thread_t *__t) |
518 | 38 | { |
519 | 38 | return pthread_join(*__t, 0); |
520 | 38 | } |
521 | | |
522 | | int __libcpp_thread_detach(__libcpp_thread_t *__t) |
523 | 8 | { |
524 | 8 | return pthread_detach(*__t); |
525 | 8 | } |
526 | | |
527 | | void __libcpp_thread_yield() |
528 | 0 | { |
529 | 0 | sched_yield(); |
530 | 0 | } |
531 | | |
532 | | void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) |
533 | 0 | { |
534 | 0 | __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns); |
535 | 0 | while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR); |
536 | 0 | } |
537 | | |
538 | | // Thread local storage |
539 | | int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *)) |
540 | 14 | { |
541 | 14 | return pthread_key_create(__key, __at_exit); |
542 | 14 | } |
543 | | |
544 | | void *__libcpp_tls_get(__libcpp_tls_key __key) |
545 | 0 | { |
546 | 0 | return pthread_getspecific(__key); |
547 | 0 | } |
548 | | |
549 | | int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) |
550 | 60.8k | { |
551 | 60.8k | return pthread_setspecific(__key, __p); |
552 | 60.8k | } |
553 | | |
554 | | #elif defined(_LIBCPP_HAS_THREAD_API_C11) |
555 | | |
556 | | int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) |
557 | | { |
558 | | return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL; |
559 | | } |
560 | | |
561 | | int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) |
562 | | { |
563 | | return mtx_lock(__m) == thrd_success ? 0 : EINVAL; |
564 | | } |
565 | | |
566 | | bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) |
567 | | { |
568 | | return mtx_trylock(__m) == thrd_success; |
569 | | } |
570 | | |
571 | | int __libcpp_recursive_mutex_unlock(__libcpp_mutex_t *__m) |
572 | | { |
573 | | return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; |
574 | | } |
575 | | |
576 | | int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) |
577 | | { |
578 | | mtx_destroy(__m); |
579 | | return 0; |
580 | | } |
581 | | |
582 | | int __libcpp_mutex_lock(__libcpp_mutex_t *__m) |
583 | | { |
584 | | return mtx_lock(__m) == thrd_success ? 0 : EINVAL; |
585 | | } |
586 | | |
587 | | bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) |
588 | | { |
589 | | return mtx_trylock(__m) == thrd_success; |
590 | | } |
591 | | |
592 | | int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) |
593 | | { |
594 | | return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; |
595 | | } |
596 | | |
597 | | int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) |
598 | | { |
599 | | mtx_destroy(__m); |
600 | | return 0; |
601 | | } |
602 | | |
603 | | // Condition Variable |
604 | | int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) |
605 | | { |
606 | | return cnd_signal(__cv) == thrd_success ? 0 : EINVAL; |
607 | | } |
608 | | |
609 | | int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) |
610 | | { |
611 | | return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL; |
612 | | } |
613 | | |
614 | | int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m) |
615 | | { |
616 | | return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL; |
617 | | } |
618 | | |
619 | | int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, |
620 | | timespec *__ts) |
621 | | { |
622 | | int __ec = cnd_timedwait(__cv, __m, __ts); |
623 | | return __ec == thrd_timedout ? ETIMEDOUT : __ec; |
624 | | } |
625 | | |
626 | | int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) |
627 | | { |
628 | | cnd_destroy(__cv); |
629 | | return 0; |
630 | | } |
631 | | |
632 | | // Execute once |
633 | | int __libcpp_execute_once(__libcpp_exec_once_flag *flag, |
634 | | void (*init_routine)(void)) { |
635 | | ::call_once(flag, init_routine); |
636 | | return 0; |
637 | | } |
638 | | |
639 | | // Thread id |
640 | | // Returns non-zero if the thread ids are equal, otherwise 0 |
641 | | bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) |
642 | | { |
643 | | return thrd_equal(t1, t2) != 0; |
644 | | } |
645 | | |
646 | | // Returns non-zero if t1 < t2, otherwise 0 |
647 | | bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) |
648 | | { |
649 | | return t1 < t2; |
650 | | } |
651 | | |
652 | | // Thread |
653 | | bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { |
654 | | return *__t == 0; |
655 | | } |
656 | | |
657 | | int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), |
658 | | void *__arg) |
659 | | { |
660 | | int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg); |
661 | | return __ec == thrd_nomem ? ENOMEM : __ec; |
662 | | } |
663 | | |
664 | | __libcpp_thread_id __libcpp_thread_get_current_id() |
665 | | { |
666 | | return thrd_current(); |
667 | | } |
668 | | |
669 | | __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) |
670 | | { |
671 | | return *__t; |
672 | | } |
673 | | |
674 | | int __libcpp_thread_join(__libcpp_thread_t *__t) |
675 | | { |
676 | | return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL; |
677 | | } |
678 | | |
679 | | int __libcpp_thread_detach(__libcpp_thread_t *__t) |
680 | | { |
681 | | return thrd_detach(*__t) == thrd_success ? 0 : EINVAL; |
682 | | } |
683 | | |
684 | | void __libcpp_thread_yield() |
685 | | { |
686 | | thrd_yield(); |
687 | | } |
688 | | |
689 | | void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) |
690 | | { |
691 | | __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns); |
692 | | thrd_sleep(&__ts, nullptr); |
693 | | } |
694 | | |
695 | | // Thread local storage |
696 | | int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *)) |
697 | | { |
698 | | return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL; |
699 | | } |
700 | | |
701 | | void *__libcpp_tls_get(__libcpp_tls_key __key) |
702 | | { |
703 | | return tss_get(__key); |
704 | | } |
705 | | |
706 | | int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) |
707 | | { |
708 | | return tss_set(__key, __p) == thrd_success ? 0 : EINVAL; |
709 | | } |
710 | | |
711 | | #endif |
712 | | |
713 | | |
714 | | #endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL |
715 | | |
716 | | class _LIBCPP_TYPE_VIS thread; |
717 | | class _LIBCPP_TYPE_VIS __thread_id; |
718 | | |
719 | | namespace this_thread |
720 | | { |
721 | | |
722 | | _LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; |
723 | | |
724 | | } // this_thread |
725 | | |
726 | | template<> struct hash<__thread_id>; |
727 | | |
728 | | class _LIBCPP_TEMPLATE_VIS __thread_id |
729 | | { |
730 | | // FIXME: pthread_t is a pointer on Darwin but a long on Linux. |
731 | | // NULL is the no-thread value on Darwin. Someone needs to check |
732 | | // on other platforms. We assume 0 works everywhere for now. |
733 | | __libcpp_thread_id __id_; |
734 | | |
735 | | public: |
736 | | _LIBCPP_INLINE_VISIBILITY |
737 | 0 | __thread_id() _NOEXCEPT : __id_(0) {} |
738 | | |
739 | | friend _LIBCPP_INLINE_VISIBILITY |
740 | | bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT |
741 | 32 | { // don't pass id==0 to underlying routines |
742 | 32 | if (__x.__id_ == 0) return __y.__id_ == 00 ; |
743 | 32 | if (__y.__id_ == 0) return false0 ; |
744 | 32 | return __libcpp_thread_id_equal(__x.__id_, __y.__id_); |
745 | 32 | } |
746 | | friend _LIBCPP_INLINE_VISIBILITY |
747 | | bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT |
748 | 0 | {return !(__x == __y);} |
749 | | friend _LIBCPP_INLINE_VISIBILITY |
750 | | bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT |
751 | 0 | { // id==0 is always less than any other thread_id |
752 | 0 | if (__x.__id_ == 0) return __y.__id_ != 0; |
753 | 0 | if (__y.__id_ == 0) return false; |
754 | 0 | return __libcpp_thread_id_less(__x.__id_, __y.__id_); |
755 | 0 | } |
756 | | friend _LIBCPP_INLINE_VISIBILITY |
757 | | bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT |
758 | 0 | {return !(__y < __x);} |
759 | | friend _LIBCPP_INLINE_VISIBILITY |
760 | | bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT |
761 | 0 | {return __y < __x ;} |
762 | | friend _LIBCPP_INLINE_VISIBILITY |
763 | | bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT |
764 | 0 | {return !(__x < __y);} |
765 | | |
766 | | _LIBCPP_INLINE_VISIBILITY |
767 | 0 | void __reset() { __id_ = 0; } |
768 | | |
769 | | template<class _CharT, class _Traits> |
770 | | friend |
771 | | _LIBCPP_INLINE_VISIBILITY |
772 | | basic_ostream<_CharT, _Traits>& |
773 | | operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id); |
774 | | |
775 | | private: |
776 | | _LIBCPP_INLINE_VISIBILITY |
777 | 34 | __thread_id(__libcpp_thread_id __id) : __id_(__id) {} |
778 | | |
779 | | friend __thread_id this_thread::get_id() _NOEXCEPT; |
780 | | friend class _LIBCPP_TYPE_VIS thread; |
781 | | friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>; |
782 | | }; |
783 | | |
784 | | namespace this_thread |
785 | | { |
786 | | |
787 | | inline _LIBCPP_INLINE_VISIBILITY |
788 | | __thread_id |
789 | | get_id() _NOEXCEPT |
790 | 2 | { |
791 | 2 | return __libcpp_thread_get_current_id(); |
792 | 2 | } |
793 | | |
794 | | } // this_thread |
795 | | |
796 | | #endif // !_LIBCPP_HAS_NO_THREADS |
797 | | |
798 | | _LIBCPP_END_NAMESPACE_STD |
799 | | |
800 | | _LIBCPP_POP_MACROS |
801 | | |
802 | | #endif // _LIBCPP_THREADING_SUPPORT |