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