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 <__availability>
14#include <__chrono/convert_to_timespec.h>
15#include <__chrono/duration.h>
16#include <__config>
17#include <__fwd/hash.h>
18#include <ctime>
19#include <errno.h>
20
21#ifdef __MVS__
22#  include <__support/ibm/nanosleep.h>
23#endif
24
25#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
26#  pragma GCC system_header
27#endif
28
29#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
30#  include <__external_threading>
31#elif !defined(_LIBCPP_HAS_NO_THREADS)
32
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.
40#    include <math.h>
41
42#    include <pthread.h>
43#    include <sched.h>
44#  elif defined(_LIBCPP_HAS_THREAD_API_C11)
45#    include <threads.h>
46#  endif
47
48#  if defined(_LIBCPP_HAS_THREAD_API_WIN32)
49#    define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_EXPORTED_FROM_ABI
50#  else
51#    define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_HIDE_FROM_ABI
52#  endif
53
54typedef ::timespec __libcpp_timespec_t;
55#endif // !defined(_LIBCPP_HAS_NO_THREADS)
56
57_LIBCPP_BEGIN_NAMESPACE_STD
58
59#if !defined(_LIBCPP_HAS_NO_THREADS)
60
61#  if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
62// Mutex
63typedef pthread_mutex_t __libcpp_mutex_t;
64#    define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
65
66typedef pthread_mutex_t __libcpp_recursive_mutex_t;
67
68// Condition Variable
69typedef pthread_cond_t __libcpp_condvar_t;
70#    define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
71
72// Execute once
73typedef pthread_once_t __libcpp_exec_once_flag;
74#    define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
75
76// Thread id
77#    if defined(__MVS__)
78typedef unsigned long long __libcpp_thread_id;
79#    else
80typedef pthread_t __libcpp_thread_id;
81#    endif
82
83// Thread
84#    define _LIBCPP_NULL_THREAD ((__libcpp_thread_t()))
85typedef pthread_t __libcpp_thread_t;
86
87// Thread Local Storage
88typedef pthread_key_t __libcpp_tls_key;
89
90#    define _LIBCPP_TLS_DESTRUCTOR_CC
91#  elif defined(_LIBCPP_HAS_THREAD_API_C11)
92// Mutex
93typedef mtx_t __libcpp_mutex_t;
94// mtx_t is a struct so using {} for initialization is valid.
95#    define _LIBCPP_MUTEX_INITIALIZER                                                                                  \
96      {}
97
98typedef mtx_t __libcpp_recursive_mutex_t;
99
100// Condition Variable
101typedef cnd_t __libcpp_condvar_t;
102// cnd_t is a struct so using {} for initialization is valid.
103#    define _LIBCPP_CONDVAR_INITIALIZER                                                                                \
104      {}
105
106// Execute once
107typedef ::once_flag __libcpp_exec_once_flag;
108#    define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT
109
110// Thread id
111typedef thrd_t __libcpp_thread_id;
112
113// Thread
114#    define _LIBCPP_NULL_THREAD 0U
115
116typedef thrd_t __libcpp_thread_t;
117
118// Thread Local Storage
119typedef tss_t __libcpp_tls_key;
120
121#    define _LIBCPP_TLS_DESTRUCTOR_CC
122#  elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
123// Mutex
124typedef void* __libcpp_mutex_t;
125#    define _LIBCPP_MUTEX_INITIALIZER 0
126
127#    if defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__arm__)
128typedef void* __libcpp_recursive_mutex_t[6];
129#    elif defined(_M_AMD64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__)
130typedef void* __libcpp_recursive_mutex_t[5];
131#    else
132#      error Unsupported architecture
133#    endif
134
135// Condition Variable
136typedef void* __libcpp_condvar_t;
137#    define _LIBCPP_CONDVAR_INITIALIZER 0
138
139// Execute Once
140typedef void* __libcpp_exec_once_flag;
141#    define _LIBCPP_EXEC_ONCE_INITIALIZER 0
142
143// Thread ID
144typedef long __libcpp_thread_id;
145
146// Thread
147#    define _LIBCPP_NULL_THREAD 0U
148
149typedef void* __libcpp_thread_t;
150
151// Thread Local Storage
152typedef long __libcpp_tls_key;
153
154#    define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall
155#  endif // !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
156
157#  if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
158// Mutex
159_LIBCPP_THREAD_ABI_VISIBILITY
160int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m);
161
162_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
163__libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m);
164
165_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool
166__libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m);
167
168_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
169__libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m);
170
171_LIBCPP_THREAD_ABI_VISIBILITY
172int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m);
173
174_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m);
175
176_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m);
177
178_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m);
179
180_LIBCPP_THREAD_ABI_VISIBILITY
181int __libcpp_mutex_destroy(__libcpp_mutex_t* __m);
182
183// Condition variable
184_LIBCPP_THREAD_ABI_VISIBILITY
185int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
186
187_LIBCPP_THREAD_ABI_VISIBILITY
188int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
189
190_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
191__libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
192
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);
195
196_LIBCPP_THREAD_ABI_VISIBILITY
197int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
198
199// Execute once
200_LIBCPP_THREAD_ABI_VISIBILITY
201int __libcpp_execute_once(__libcpp_exec_once_flag* __flag, void (*__init_routine)());
202
203// Thread id
204_LIBCPP_THREAD_ABI_VISIBILITY
205bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2);
206
207_LIBCPP_THREAD_ABI_VISIBILITY
208bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2);
209
210// Thread
211_LIBCPP_THREAD_ABI_VISIBILITY
212bool __libcpp_thread_isnull(const __libcpp_thread_t* __t);
213
214_LIBCPP_THREAD_ABI_VISIBILITY
215int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg);
216
217_LIBCPP_THREAD_ABI_VISIBILITY
218__libcpp_thread_id __libcpp_thread_get_current_id();
219
220_LIBCPP_THREAD_ABI_VISIBILITY
221__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t);
222
223_LIBCPP_THREAD_ABI_VISIBILITY
224int __libcpp_thread_join(__libcpp_thread_t* __t);
225
226_LIBCPP_THREAD_ABI_VISIBILITY
227int __libcpp_thread_detach(__libcpp_thread_t* __t);
228
229_LIBCPP_THREAD_ABI_VISIBILITY
230void __libcpp_thread_yield();
231
232_LIBCPP_THREAD_ABI_VISIBILITY
233void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns);
234
235// Thread local storage
236_LIBCPP_THREAD_ABI_VISIBILITY
237int __libcpp_tls_create(__libcpp_tls_key* __key, void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
238
239_LIBCPP_THREAD_ABI_VISIBILITY
240void* __libcpp_tls_get(__libcpp_tls_key __key);
241
242_LIBCPP_THREAD_ABI_VISIBILITY
243int __libcpp_tls_set(__libcpp_tls_key __key, void* __p);
244
245#  endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
246
247#  if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
248
249int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
250  pthread_mutexattr_t __attr;
251  int __ec = pthread_mutexattr_init(&__attr);
252  if (__ec)
253    return __ec;
254  __ec = pthread_mutexattr_settype(&__attr, PTHREAD_MUTEX_RECURSIVE);
255  if (__ec) {
256    pthread_mutexattr_destroy(&__attr);
257    return __ec;
258  }
259  __ec = pthread_mutex_init(__m, &__attr);
260  if (__ec) {
261    pthread_mutexattr_destroy(&__attr);
262    return __ec;
263  }
264  __ec = pthread_mutexattr_destroy(&__attr);
265  if (__ec) {
266    pthread_mutex_destroy(__m);
267    return __ec;
268  }
269  return 0;
270}
271
272int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_lock(__m); }
273
274bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_trylock(__m) == 0; }
275
276int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_unlock(__m); }
277
278int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_destroy(__m); }
279
280int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { return pthread_mutex_lock(__m); }
281
282bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return pthread_mutex_trylock(__m) == 0; }
283
284int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { return pthread_mutex_unlock(__m); }
285
286int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) { return pthread_mutex_destroy(__m); }
287
288// Condition Variable
289int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) { return pthread_cond_signal(__cv); }
290
291int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) { return pthread_cond_broadcast(__cv); }
292
293int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) { return pthread_cond_wait(__cv, __m); }
294
295int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts) {
296  return pthread_cond_timedwait(__cv, __m, __ts);
297}
298
299int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) { return pthread_cond_destroy(__cv); }
300
301// Execute once
302int __libcpp_execute_once(__libcpp_exec_once_flag* __flag, void (*__init_routine)()) {
303  return pthread_once(__flag, __init_routine);
304}
305
306// Thread id
307// Returns non-zero if the thread ids are equal, otherwise 0
308bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) { return __t1 == __t2; }
309
310// Returns non-zero if t1 < t2, otherwise 0
311bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) { return __t1 < __t2; }
312
313// Thread
314bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return __libcpp_thread_get_id(__t) == 0; }
315
316int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
317  return pthread_create(__t, nullptr, __func, __arg);
318}
319
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);
323}
324
325__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) {
326#    if defined(__MVS__)
327  return __t->__;
328#    else
329  return *__t;
330#    endif
331}
332
333int __libcpp_thread_join(__libcpp_thread_t* __t) { return pthread_join(*__t, nullptr); }
334
335int __libcpp_thread_detach(__libcpp_thread_t* __t) { return pthread_detach(*__t); }
336
337void __libcpp_thread_yield() { sched_yield(); }
338
339void __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)
342    ;
343}
344
345// Thread local storage
346int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
347  return pthread_key_create(__key, __at_exit);
348}
349
350void* __libcpp_tls_get(__libcpp_tls_key __key) { return pthread_getspecific(__key); }
351
352int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) { return pthread_setspecific(__key, __p); }
353
354#  elif defined(_LIBCPP_HAS_THREAD_API_C11)
355
356int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
357  return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
358}
359
360int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) {
361  return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
362}
363
364bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { return mtx_trylock(__m) == thrd_success; }
365
366int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) {
367  return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
368}
369
370int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) {
371  mtx_destroy(__m);
372  return 0;
373}
374
375int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { return mtx_lock(__m) == thrd_success ? 0 : EINVAL; }
376
377bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return mtx_trylock(__m) == thrd_success; }
378
379int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; }
380
381int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
382  mtx_destroy(__m);
383  return 0;
384}
385
386// Condition Variable
387int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) { return cnd_signal(__cv) == thrd_success ? 0 : EINVAL; }
388
389int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) { return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL; }
390
391int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) {
392  return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
393}
394
395int __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;
398}
399
400int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) {
401  cnd_destroy(__cv);
402  return 0;
403}
404
405// Execute once
406int __libcpp_execute_once(__libcpp_exec_once_flag* flag, void (*init_routine)(void)) {
407  ::call_once(flag, init_routine);
408  return 0;
409}
410
411// Thread id
412// Returns non-zero if the thread ids are equal, otherwise 0
413bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) { return thrd_equal(t1, t2) != 0; }
414
415// Returns non-zero if t1 < t2, otherwise 0
416bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) { return t1 < t2; }
417
418// Thread
419bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return __libcpp_thread_get_id(__t) == 0; }
420
421int __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;
424}
425
426__libcpp_thread_id __libcpp_thread_get_current_id() { return thrd_current(); }
427
428__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) { return *__t; }
429
430int __libcpp_thread_join(__libcpp_thread_t* __t) { return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL; }
431
432int __libcpp_thread_detach(__libcpp_thread_t* __t) { return thrd_detach(*__t) == thrd_success ? 0 : EINVAL; }
433
434void __libcpp_thread_yield() { thrd_yield(); }
435
436void __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);
439}
440
441// Thread local storage
442int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
443  return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
444}
445
446void* __libcpp_tls_get(__libcpp_tls_key __key) { return tss_get(__key); }
447
448int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) { return tss_set(__key, __p) == thrd_success ? 0 : EINVAL; }
449
450#  endif
451
452#endif // !_LIBCPP_HAS_NO_THREADS
453
454_LIBCPP_END_NAMESPACE_STD
455
456#endif // _LIBCPP___THREADING_SUPPORT
457