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 <errno.h>
16
17#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
18#pragma GCC system_header
19#endif
20
21#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
22# include <__external_threading>
23#elif !defined(_LIBCPP_HAS_NO_THREADS)
24
25typedef ::timespec __libcpp_timespec_t;
26
27#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
28# include <pthread.h>
29# include <sched.h>
30#endif
31
32_LIBCPP_PUSH_MACROS
33#include <__undef_macros>
34
35#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
36 defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL) || \
37 defined(_LIBCPP_HAS_THREAD_API_WIN32)
38#define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS
39#else
40#define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
41#endif
42
43#if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(no_thread_safety_analysis)
44#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
45#else
46#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
47#endif
48
49_LIBCPP_BEGIN_NAMESPACE_STD
50
51#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
52// Mutex
53typedef pthread_mutex_t __libcpp_mutex_t;
54#define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
55
56typedef pthread_mutex_t __libcpp_recursive_mutex_t;
57
58// Condition Variable
59typedef pthread_cond_t __libcpp_condvar_t;
60#define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
61
62// Execute once
63typedef pthread_once_t __libcpp_exec_once_flag;
64#define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
65
66// Thread id
67typedef pthread_t __libcpp_thread_id;
68
69// Thread
70#define _LIBCPP_NULL_THREAD 0U
71
72typedef pthread_t __libcpp_thread_t;
73
74// Thread Local Storage
75typedef pthread_key_t __libcpp_tls_key;
76
77#define _LIBCPP_TLS_DESTRUCTOR_CC
78#else
79// Mutex
80typedef void* __libcpp_mutex_t;
81#define _LIBCPP_MUTEX_INITIALIZER 0
82
83#if defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__arm__)
84typedef void* __libcpp_recursive_mutex_t[6];
85#elif defined(_M_AMD64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__)
86typedef void* __libcpp_recursive_mutex_t[5];
87#else
88# error Unsupported architecture
89#endif
90
91// Condition Variable
92typedef void* __libcpp_condvar_t;
93#define _LIBCPP_CONDVAR_INITIALIZER 0
94
95// Execute Once
96typedef void* __libcpp_exec_once_flag;
97#define _LIBCPP_EXEC_ONCE_INITIALIZER 0
98
99// Thread ID
100typedef long __libcpp_thread_id;
101
102// Thread
103#define _LIBCPP_NULL_THREAD 0U
104
105typedef void* __libcpp_thread_t;
106
107// Thread Local Storage
108typedef long __libcpp_tls_key;
109
110#define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall
111#endif
112
113// Mutex
114_LIBCPP_THREAD_ABI_VISIBILITY
115int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m);
116
117_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
118int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m);
119
120_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
121bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m);
122
123_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
124int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m);
125
126_LIBCPP_THREAD_ABI_VISIBILITY
127int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m);
128
129_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
130int __libcpp_mutex_lock(__libcpp_mutex_t *__m);
131
132_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
133bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m);
134
135_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
136int __libcpp_mutex_unlock(__libcpp_mutex_t *__m);
137
138_LIBCPP_THREAD_ABI_VISIBILITY
139int __libcpp_mutex_destroy(__libcpp_mutex_t *__m);
140
141// Condition variable
142_LIBCPP_THREAD_ABI_VISIBILITY
143int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
144
145_LIBCPP_THREAD_ABI_VISIBILITY
146int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
147
148_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
149int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
150
151_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
152int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
153 __libcpp_timespec_t *__ts);
154
155_LIBCPP_THREAD_ABI_VISIBILITY
156int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
157
158// Execute once
159_LIBCPP_THREAD_ABI_VISIBILITY
160int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
161 void (*init_routine)());
162
163// Thread id
164_LIBCPP_THREAD_ABI_VISIBILITY
165bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2);
166
167_LIBCPP_THREAD_ABI_VISIBILITY
168bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2);
169
170// Thread
171_LIBCPP_THREAD_ABI_VISIBILITY
172bool __libcpp_thread_isnull(const __libcpp_thread_t *__t);
173
174_LIBCPP_THREAD_ABI_VISIBILITY
175int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
176 void *__arg);
177
178_LIBCPP_THREAD_ABI_VISIBILITY
179__libcpp_thread_id __libcpp_thread_get_current_id();
180
181_LIBCPP_THREAD_ABI_VISIBILITY
182__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t);
183
184_LIBCPP_THREAD_ABI_VISIBILITY
185int __libcpp_thread_join(__libcpp_thread_t *__t);
186
187_LIBCPP_THREAD_ABI_VISIBILITY
188int __libcpp_thread_detach(__libcpp_thread_t *__t);
189
190_LIBCPP_THREAD_ABI_VISIBILITY
191void __libcpp_thread_yield();
192
193_LIBCPP_THREAD_ABI_VISIBILITY
194void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns);
195
196// Thread local storage
197_LIBCPP_THREAD_ABI_VISIBILITY
198int __libcpp_tls_create(__libcpp_tls_key* __key,
199 void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
200
201_LIBCPP_THREAD_ABI_VISIBILITY
202void *__libcpp_tls_get(__libcpp_tls_key __key);
203
204_LIBCPP_THREAD_ABI_VISIBILITY
205int __libcpp_tls_set(__libcpp_tls_key __key, void *__p);
206
207#if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
208 defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) && \
209 defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
210
211int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
212{
213 pthread_mutexattr_t attr;
214 int __ec = pthread_mutexattr_init(&attr);
215 if (__ec)
216 return __ec;
217 __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
218 if (__ec) {
219 pthread_mutexattr_destroy(&attr);
220 return __ec;
221 }
222 __ec = pthread_mutex_init(__m, &attr);
223 if (__ec) {
224 pthread_mutexattr_destroy(&attr);
225 return __ec;
226 }
227 __ec = pthread_mutexattr_destroy(&attr);
228 if (__ec) {
229 pthread_mutex_destroy(__m);
230 return __ec;
231 }
232 return 0;
233}
234
235int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
236{
237 return pthread_mutex_lock(__m);
238}
239
240bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
241{
242 return pthread_mutex_trylock(__m) == 0;
243}
244
245int __libcpp_recursive_mutex_unlock(__libcpp_mutex_t *__m)
246{
247 return pthread_mutex_unlock(__m);
248}
249
250int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
251{
252 return pthread_mutex_destroy(__m);
253}
254
255int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
256{
257 return pthread_mutex_lock(__m);
258}
259
260bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
261{
262 return pthread_mutex_trylock(__m) == 0;
263}
264
265int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
266{
267 return pthread_mutex_unlock(__m);
268}
269
270int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
271{
272 return pthread_mutex_destroy(__m);
273}
274
275// Condition Variable
276int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
277{
278 return pthread_cond_signal(__cv);
279}
280
281int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
282{
283 return pthread_cond_broadcast(__cv);
284}
285
286int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
287{
288 return pthread_cond_wait(__cv, __m);
289}
290
291int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
292 __libcpp_timespec_t *__ts)
293{
294 return pthread_cond_timedwait(__cv, __m, __ts);
295}
296
297int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
298{
299 return pthread_cond_destroy(__cv);
300}
301
302// Execute once
303int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
304 void (*init_routine)()) {
305 return pthread_once(flag, init_routine);
306}
307
308// Thread id
309// Returns non-zero if the thread ids are equal, otherwise 0
310bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2)
311{
312 return pthread_equal(t1, t2) != 0;
313}
314
315// Returns non-zero if t1 < t2, otherwise 0
316bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2)
317{
318 return t1 < t2;
319}
320
321// Thread
322bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
323 return *__t == 0;
324}
325
326int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
327 void *__arg)
328{
329 return pthread_create(__t, 0, __func, __arg);
330}
331
332__libcpp_thread_id __libcpp_thread_get_current_id()
333{
334 return pthread_self();
335}
336
337__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
338{
339 return *__t;
340}
341
342int __libcpp_thread_join(__libcpp_thread_t *__t)
343{
344 return pthread_join(*__t, 0);
345}
346
347int __libcpp_thread_detach(__libcpp_thread_t *__t)
348{
349 return pthread_detach(*__t);
350}
351
352void __libcpp_thread_yield()
353{
354 sched_yield();
355}
356
357void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
358{
359 using namespace chrono;
360 seconds __s = duration_cast<seconds>(__ns);
361 __libcpp_timespec_t __ts;
362 typedef decltype(__ts.tv_sec) ts_sec;
363 _LIBCPP_CONSTEXPR ts_sec __ts_sec_max = numeric_limits<ts_sec>::max();
364
365 if (__s.count() < __ts_sec_max)
366 {
367 __ts.tv_sec = static_cast<ts_sec>(__s.count());
368 __ts.tv_nsec = static_cast<decltype(__ts.tv_nsec)>((__ns - __s).count());
369 }
370 else
371 {
372 __ts.tv_sec = __ts_sec_max;
373 __ts.tv_nsec = 999999999; // (10^9 - 1)
374 }
375
376 while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR);
377}
378
379// Thread local storage
380int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
381{
382 return pthread_key_create(__key, __at_exit);
383}
384
385void *__libcpp_tls_get(__libcpp_tls_key __key)
386{
387 return pthread_getspecific(__key);
388}
389
390int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
391{
392 return pthread_setspecific(__key, __p);
393}
394
395#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
396
397_LIBCPP_END_NAMESPACE_STD
398
399_LIBCPP_POP_MACROS
400
401#endif // !_LIBCPP_HAS_NO_THREADS
402
403#endif // _LIBCPP_THREADING_SUPPORT
404