2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___THREADING_SUPPORT
11 #define _LIBCPP___THREADING_SUPPORT
13 #include <__availability>
14 #include <__chrono/convert_to_timespec.h>
15 #include <__chrono/duration.h>
17 #include <__fwd/hash.h>
22 # include <__support/ibm/nanosleep.h>
25 #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
26 # pragma GCC system_header
29 #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
30 # include <__external_threading>
31 #elif !defined(_LIBCPP_HAS_NO_THREADS)
33 # if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
34 // Some platforms require <bits/atomic_wide_counter.h> in order for
35 // PTHREAD_COND_INITIALIZER to be expanded. Normally that would come
36 // in via <pthread.h>, but it's a non-modular header on those platforms,
37 // so libc++'s <math.h> usually absorbs atomic_wide_counter.h into the
38 // module with <math.h> and makes atomic_wide_counter.h invisible.
39 // Include <math.h> here to work around that.
44 # elif defined(_LIBCPP_HAS_THREAD_API_C11)
48 # if defined(_LIBCPP_HAS_THREAD_API_WIN32)
49 # define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_EXPORTED_FROM_ABI
51 # define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_HIDE_FROM_ABI
54 typedef ::timespec __libcpp_timespec_t;
55 #endif // !defined(_LIBCPP_HAS_NO_THREADS)
57 _LIBCPP_BEGIN_NAMESPACE_STD
59 #if !defined(_LIBCPP_HAS_NO_THREADS)
61 # if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
63 typedef pthread_mutex_t __libcpp_mutex_t;
64 # define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
66 typedef pthread_mutex_t __libcpp_recursive_mutex_t;
69 typedef pthread_cond_t __libcpp_condvar_t;
70 # define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
73 typedef pthread_once_t __libcpp_exec_once_flag;
74 # define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
78 typedef unsigned long long __libcpp_thread_id;
80 typedef pthread_t __libcpp_thread_id;
84 # define _LIBCPP_NULL_THREAD ((__libcpp_thread_t()))
85 typedef pthread_t __libcpp_thread_t;
87 // Thread Local Storage
88 typedef pthread_key_t __libcpp_tls_key;
90 # define _LIBCPP_TLS_DESTRUCTOR_CC
91 # elif defined(_LIBCPP_HAS_THREAD_API_C11)
93 typedef mtx_t __libcpp_mutex_t;
94 // mtx_t is a struct so using {} for initialization is valid.
95 # define _LIBCPP_MUTEX_INITIALIZER \
98 typedef mtx_t __libcpp_recursive_mutex_t;
100 // Condition Variable
101 typedef cnd_t __libcpp_condvar_t;
102 // cnd_t is a struct so using {} for initialization is valid.
103 # define _LIBCPP_CONDVAR_INITIALIZER \
107 typedef ::once_flag __libcpp_exec_once_flag;
108 # define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT
111 typedef thrd_t __libcpp_thread_id;
114 # define _LIBCPP_NULL_THREAD 0U
116 typedef thrd_t __libcpp_thread_t;
118 // Thread Local Storage
119 typedef tss_t __libcpp_tls_key;
121 # define _LIBCPP_TLS_DESTRUCTOR_CC
122 # elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
124 typedef void* __libcpp_mutex_t;
125 # define _LIBCPP_MUTEX_INITIALIZER 0
127 # if defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__arm__)
128 typedef void* __libcpp_recursive_mutex_t[6];
129 # elif defined(_M_AMD64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__)
130 typedef void* __libcpp_recursive_mutex_t[5];
132 # error Unsupported architecture
135 // Condition Variable
136 typedef void* __libcpp_condvar_t;
137 # define _LIBCPP_CONDVAR_INITIALIZER 0
140 typedef void* __libcpp_exec_once_flag;
141 # define _LIBCPP_EXEC_ONCE_INITIALIZER 0
144 typedef long __libcpp_thread_id;
147 # define _LIBCPP_NULL_THREAD 0U
149 typedef void* __libcpp_thread_t;
151 // Thread Local Storage
152 typedef long __libcpp_tls_key;
154 # define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall
155 # endif // !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
157 # if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
159 _LIBCPP_THREAD_ABI_VISIBILITY
160 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m);
162 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
163 __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m);
165 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool
166 __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m);
168 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
169 __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m);
171 _LIBCPP_THREAD_ABI_VISIBILITY
172 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m);
174 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m);
176 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m);
178 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m);
180 _LIBCPP_THREAD_ABI_VISIBILITY
181 int __libcpp_mutex_destroy(__libcpp_mutex_t* __m);
183 // Condition variable
184 _LIBCPP_THREAD_ABI_VISIBILITY
185 int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
187 _LIBCPP_THREAD_ABI_VISIBILITY
188 int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
190 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
191 __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
193 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
194 __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts);
196 _LIBCPP_THREAD_ABI_VISIBILITY
197 int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
200 _LIBCPP_THREAD_ABI_VISIBILITY
201 int __libcpp_execute_once(__libcpp_exec_once_flag* __flag, void (*__init_routine)());
204 _LIBCPP_THREAD_ABI_VISIBILITY
205 bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2);
207 _LIBCPP_THREAD_ABI_VISIBILITY
208 bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2);
211 _LIBCPP_THREAD_ABI_VISIBILITY
212 bool __libcpp_thread_isnull(const __libcpp_thread_t* __t);
214 _LIBCPP_THREAD_ABI_VISIBILITY
215 int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg);
217 _LIBCPP_THREAD_ABI_VISIBILITY
218 __libcpp_thread_id __libcpp_thread_get_current_id();
220 _LIBCPP_THREAD_ABI_VISIBILITY
221 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t);
223 _LIBCPP_THREAD_ABI_VISIBILITY
224 int __libcpp_thread_join(__libcpp_thread_t* __t);
226 _LIBCPP_THREAD_ABI_VISIBILITY
227 int __libcpp_thread_detach(__libcpp_thread_t* __t);
229 _LIBCPP_THREAD_ABI_VISIBILITY
230 void __libcpp_thread_yield();
232 _LIBCPP_THREAD_ABI_VISIBILITY
233 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns);
235 // Thread local storage
236 _LIBCPP_THREAD_ABI_VISIBILITY
237 int __libcpp_tls_create(__libcpp_tls_key* __key, void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
239 _LIBCPP_THREAD_ABI_VISIBILITY
240 void* __libcpp_tls_get(__libcpp_tls_key __key);
242 _LIBCPP_THREAD_ABI_VISIBILITY
243 int __libcpp_tls_set(__libcpp_tls_key __key, void* __p);
245 # endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
247 # if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
249 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
250 pthread_mutexattr_t __attr;
251 int __ec = pthread_mutexattr_init(&__attr);
254 __ec = pthread_mutexattr_settype(&__attr, PTHREAD_MUTEX_RECURSIVE);
256 pthread_mutexattr_destroy(&__attr);
259 __ec = pthread_mutex_init(__m, &__attr);
261 pthread_mutexattr_destroy(&__attr);
264 __ec = pthread_mutexattr_destroy(&__attr);
266 pthread_mutex_destroy(__m);
272 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_lock(__m); }
274 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_trylock(__m) == 0; }
276 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_unlock(__m); }
278 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_destroy(__m); }
280 int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { return pthread_mutex_lock(__m); }
282 bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return pthread_mutex_trylock(__m) == 0; }
284 int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { return pthread_mutex_unlock(__m); }
286 int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) { return pthread_mutex_destroy(__m); }
288 // Condition Variable
289 int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) { return pthread_cond_signal(__cv); }
291 int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) { return pthread_cond_broadcast(__cv); }
293 int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) { return pthread_cond_wait(__cv, __m); }
295 int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts) {
296 return pthread_cond_timedwait(__cv, __m, __ts);
299 int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) { return pthread_cond_destroy(__cv); }
302 int __libcpp_execute_once(__libcpp_exec_once_flag* __flag, void (*__init_routine)()) {
303 return pthread_once(__flag, __init_routine);
307 // Returns non-zero if the thread ids are equal, otherwise 0
308 bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) { return __t1 == __t2; }
310 // Returns non-zero if t1 < t2, otherwise 0
311 bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) { return __t1 < __t2; }
314 bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return __libcpp_thread_get_id(__t) == 0; }
316 int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
317 return pthread_create(__t, nullptr, __func, __arg);
320 __libcpp_thread_id __libcpp_thread_get_current_id() {
321 const __libcpp_thread_t __current_thread = pthread_self();
322 return __libcpp_thread_get_id(&__current_thread);
325 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) {
326 # if defined(__MVS__)
333 int __libcpp_thread_join(__libcpp_thread_t* __t) { return pthread_join(*__t, nullptr); }
335 int __libcpp_thread_detach(__libcpp_thread_t* __t) { return pthread_detach(*__t); }
337 void __libcpp_thread_yield() { sched_yield(); }
339 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
340 __libcpp_timespec_t __ts = std::__convert_to_timespec<__libcpp_timespec_t>(__ns);
341 while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
345 // Thread local storage
346 int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
347 return pthread_key_create(__key, __at_exit);
350 void* __libcpp_tls_get(__libcpp_tls_key __key) { return pthread_getspecific(__key); }
352 int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) { return pthread_setspecific(__key, __p); }
354 # elif defined(_LIBCPP_HAS_THREAD_API_C11)
356 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
357 return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
360 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) {
361 return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
364 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { return mtx_trylock(__m) == thrd_success; }
366 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) {
367 return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
370 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) {
375 int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { return mtx_lock(__m) == thrd_success ? 0 : EINVAL; }
377 bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return mtx_trylock(__m) == thrd_success; }
379 int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; }
381 int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
386 // Condition Variable
387 int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) { return cnd_signal(__cv) == thrd_success ? 0 : EINVAL; }
389 int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) { return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL; }
391 int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) {
392 return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
395 int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts) {
396 int __ec = cnd_timedwait(__cv, __m, __ts);
397 return __ec == thrd_timedout ? ETIMEDOUT : __ec;
400 int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) {
406 int __libcpp_execute_once(__libcpp_exec_once_flag* flag, void (*init_routine)(void)) {
407 ::call_once(flag, init_routine);
412 // Returns non-zero if the thread ids are equal, otherwise 0
413 bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) { return thrd_equal(t1, t2) != 0; }
415 // Returns non-zero if t1 < t2, otherwise 0
416 bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) { return t1 < t2; }
419 bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return __libcpp_thread_get_id(__t) == 0; }
421 int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
422 int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg);
423 return __ec == thrd_nomem ? ENOMEM : __ec;
426 __libcpp_thread_id __libcpp_thread_get_current_id() { return thrd_current(); }
428 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) { return *__t; }
430 int __libcpp_thread_join(__libcpp_thread_t* __t) { return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL; }
432 int __libcpp_thread_detach(__libcpp_thread_t* __t) { return thrd_detach(*__t) == thrd_success ? 0 : EINVAL; }
434 void __libcpp_thread_yield() { thrd_yield(); }
436 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
437 __libcpp_timespec_t __ts = std::__convert_to_timespec<__libcpp_timespec_t>(__ns);
438 thrd_sleep(&__ts, nullptr);
441 // Thread local storage
442 int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
443 return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
446 void* __libcpp_tls_get(__libcpp_tls_key __key) { return tss_get(__key); }
448 int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) { return tss_set(__key, __p) == thrd_success ? 0 : EINVAL; }
452 #endif // !_LIBCPP_HAS_NO_THREADS
454 _LIBCPP_END_NAMESPACE_STD
456 #endif // _LIBCPP___THREADING_SUPPORT