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