1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef _LIBCPP_THREADING_SUPPORT
12#define _LIBCPP_THREADING_SUPPORT
13
14#include <__config>
15
16#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
17#pragma GCC system_header
18#endif
19
20#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
21# include <__external_threading>
22#elif !defined(_LIBCPP_HAS_NO_THREADS)
23
24#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
25# include <pthread.h>
26# include <sched.h>
27#elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
28#include <assert.h>
29#include <Windows.h>
30#include <process.h>
31#include <fibersapi.h>
32
33#include <chrono>
34#endif
35
36#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
37    defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)
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
70typedef pthread_t __libcpp_thread_t;
71
72// Thrad Local Storage
73typedef pthread_key_t __libcpp_tls_key;
74
75#define _LIBCPP_TLS_DESTRUCTOR_CC
76#else
77// Mutex
78typedef SRWLOCK __libcpp_mutex_t;
79#define _LIBCPP_MUTEX_INITIALIZER SRWLOCK_INIT
80
81typedef CRITICAL_SECTION __libcpp_recursive_mutex_t;
82
83// Condition Variable
84typedef CONDITION_VARIABLE __libcpp_condvar_t;
85#define _LIBCPP_CONDVAR_INITIALIZER CONDITION_VARIABLE_INIT
86
87// Execute Once
88typedef INIT_ONCE __libcpp_exec_once_flag;
89#define _LIBCPP_EXEC_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT
90
91// Thread ID
92typedef DWORD __libcpp_thread_id;
93
94// Thread
95typedef HANDLE __libcpp_thread_t;
96
97// Thread Local Storage
98typedef DWORD __libcpp_tls_key;
99
100#define _LIBCPP_TLS_DESTRUCTOR_CC WINAPI
101#endif
102
103// Mutex
104_LIBCPP_THREAD_ABI_VISIBILITY
105int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m);
106
107_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
108int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m);
109
110_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
111int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m);
112
113_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
114int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m);
115
116_LIBCPP_THREAD_ABI_VISIBILITY
117int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m);
118
119_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
120int __libcpp_mutex_lock(__libcpp_mutex_t *__m);
121
122_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
123int __libcpp_mutex_trylock(__libcpp_mutex_t *__m);
124
125_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
126int __libcpp_mutex_unlock(__libcpp_mutex_t *__m);
127
128_LIBCPP_THREAD_ABI_VISIBILITY
129int __libcpp_mutex_destroy(__libcpp_mutex_t *__m);
130
131// Condition variable
132_LIBCPP_THREAD_ABI_VISIBILITY
133int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
134
135_LIBCPP_THREAD_ABI_VISIBILITY
136int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
137
138_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
139int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
140
141_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
142int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
143                               timespec *__ts);
144
145_LIBCPP_THREAD_ABI_VISIBILITY
146int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
147
148// Execute once
149_LIBCPP_THREAD_ABI_VISIBILITY
150int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
151                          void (*init_routine)(void));
152
153// Thread id
154#if defined(__APPLE__) && !defined(__arm__)
155_LIBCPP_THREAD_ABI_VISIBILITY
156mach_port_t __libcpp_thread_get_port();
157#endif
158
159_LIBCPP_THREAD_ABI_VISIBILITY
160bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2);
161
162_LIBCPP_THREAD_ABI_VISIBILITY
163bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2);
164
165// Thread
166_LIBCPP_THREAD_ABI_VISIBILITY
167int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
168                           void *__arg);
169
170_LIBCPP_THREAD_ABI_VISIBILITY
171__libcpp_thread_id __libcpp_thread_get_current_id();
172
173_LIBCPP_THREAD_ABI_VISIBILITY
174__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t);
175
176_LIBCPP_THREAD_ABI_VISIBILITY
177int __libcpp_thread_join(__libcpp_thread_t *__t);
178
179_LIBCPP_THREAD_ABI_VISIBILITY
180int __libcpp_thread_detach(__libcpp_thread_t *__t);
181
182_LIBCPP_THREAD_ABI_VISIBILITY
183void __libcpp_thread_yield();
184
185// Thread local storage
186_LIBCPP_THREAD_ABI_VISIBILITY
187int __libcpp_tls_create(__libcpp_tls_key* __key,
188                        void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
189
190_LIBCPP_THREAD_ABI_VISIBILITY
191void *__libcpp_tls_get(__libcpp_tls_key __key);
192
193_LIBCPP_THREAD_ABI_VISIBILITY
194int __libcpp_tls_set(__libcpp_tls_key __key, void *__p);
195
196#if !defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
197    defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)
198
199#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
200
201int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
202{
203  pthread_mutexattr_t attr;
204  int __ec = pthread_mutexattr_init(&attr);
205  if (__ec)
206    return __ec;
207  __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
208  if (__ec) {
209    pthread_mutexattr_destroy(&attr);
210    return __ec;
211  }
212  __ec = pthread_mutex_init(__m, &attr);
213  if (__ec) {
214    pthread_mutexattr_destroy(&attr);
215    return __ec;
216  }
217  __ec = pthread_mutexattr_destroy(&attr);
218  if (__ec) {
219    pthread_mutex_destroy(__m);
220    return __ec;
221  }
222  return 0;
223}
224
225int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
226{
227  return pthread_mutex_lock(__m);
228}
229
230int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
231{
232  return pthread_mutex_trylock(__m);
233}
234
235int __libcpp_recursive_mutex_unlock(__libcpp_mutex_t *__m)
236{
237  return pthread_mutex_unlock(__m);
238}
239
240int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
241{
242  return pthread_mutex_destroy(__m);
243}
244
245int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
246{
247  return pthread_mutex_lock(__m);
248}
249
250int __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
251{
252  return pthread_mutex_trylock(__m);
253}
254
255int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
256{
257  return pthread_mutex_unlock(__m);
258}
259
260int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
261{
262  return pthread_mutex_destroy(__m);
263}
264
265// Condition Variable
266int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
267{
268  return pthread_cond_signal(__cv);
269}
270
271int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
272{
273  return pthread_cond_broadcast(__cv);
274}
275
276int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
277{
278  return pthread_cond_wait(__cv, __m);
279}
280
281int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
282                               timespec *__ts)
283{
284  return pthread_cond_timedwait(__cv, __m, __ts);
285}
286
287int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
288{
289  return pthread_cond_destroy(__cv);
290}
291
292// Execute once
293int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
294                          void (*init_routine)(void)) {
295  return pthread_once(flag, init_routine);
296}
297
298// Thread id
299#if defined(__APPLE__) && !defined(__arm__)
300mach_port_t __libcpp_thread_get_port() {
301    return pthread_mach_thread_np(pthread_self());
302}
303#endif
304
305// Returns non-zero if the thread ids are equal, otherwise 0
306bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2)
307{
308  return pthread_equal(t1, t2) != 0;
309}
310
311// Returns non-zero if t1 < t2, otherwise 0
312bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2)
313{
314  return t1 < t2;
315}
316
317// Thread
318int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
319                           void *__arg)
320{
321  return pthread_create(__t, 0, __func, __arg);
322}
323
324__libcpp_thread_id __libcpp_thread_get_current_id()
325{
326  return pthread_self();
327}
328
329__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
330{
331  return *__t;
332}
333
334int __libcpp_thread_join(__libcpp_thread_t *__t)
335{
336  return pthread_join(*__t, 0);
337}
338
339int __libcpp_thread_detach(__libcpp_thread_t *__t)
340{
341  return pthread_detach(*__t);
342}
343
344void __libcpp_thread_yield()
345{
346  sched_yield();
347}
348
349// Thread local storage
350int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
351{
352  return pthread_key_create(__key, __at_exit);
353}
354
355void *__libcpp_tls_get(__libcpp_tls_key __key)
356{
357  return pthread_getspecific(__key);
358}
359
360int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
361{
362    return pthread_setspecific(__key, __p);
363}
364
365#elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
366
367// Mutex
368int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
369{
370  InitializeCriticalSection(__m);
371  return 0;
372}
373
374int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
375{
376  EnterCriticalSection(__m);
377  return 0;
378}
379
380int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
381{
382  TryEnterCriticalSection(__m);
383  return 0;
384}
385
386int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
387{
388  LeaveCriticalSection(__m);
389  return 0;
390}
391
392int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
393{
394  DeleteCriticalSection(__m);
395  return 0;
396}
397
398int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
399{
400  AcquireSRWLockExclusive(__m);
401  return 0;
402}
403
404int __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
405{
406  TryAcquireSRWLockExclusive(__m);
407  return 0;
408}
409
410int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
411{
412  ReleaseSRWLockExclusive(__m);
413  return 0;
414}
415
416int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
417{
418  static_cast<void>(__m);
419  return 0;
420}
421
422// Condition Variable
423int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
424{
425  WakeConditionVariable(__cv);
426  return 0;
427}
428
429int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
430{
431  WakeAllConditionVariable(__cv);
432  return 0;
433}
434
435int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
436{
437  SleepConditionVariableSRW(__cv, __m, INFINITE, 0);
438  return 0;
439}
440
441int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
442                               timespec *__ts)
443{
444  using namespace _VSTD::chrono;
445
446  auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
447  auto abstime =
448      system_clock::time_point(duration_cast<system_clock::duration>(duration));
449  auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
450
451  if (!SleepConditionVariableSRW(__cv, __m,
452                                 timeout_ms.count() > 0 ? timeout_ms.count()
453                                                        : 0,
454                                 0))
455    return GetLastError();
456  return 0;
457}
458
459int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
460{
461  static_cast<void>(__cv);
462  return 0;
463}
464
465// Execute Once
466static inline _LIBCPP_ALWAYS_INLINE BOOL CALLBACK
467__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
468                                      PVOID *__context)
469{
470  static_cast<void>(__init_once);
471  static_cast<void>(__context);
472
473  void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
474  init_routine();
475  return TRUE;
476}
477
478int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
479                          void (*__init_routine)(void))
480{
481  if (!InitOnceExecuteOnce(__flag, __libcpp_init_once_execute_once_thunk,
482                           reinterpret_cast<void *>(__init_routine), NULL))
483    return GetLastError();
484  return 0;
485}
486
487// Thread ID
488bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
489                              __libcpp_thread_id __rhs)
490{
491  return __lhs == __rhs;
492}
493
494bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
495{
496  return __lhs < __rhs;
497}
498
499// Thread
500struct __libcpp_beginthreadex_thunk_data
501{
502  void *(*__func)(void *);
503  void *__arg;
504};
505
506static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI
507__libcpp_beginthreadex_thunk(void *__data)
508{
509  __libcpp_beginthreadex_thunk_data data =
510      *reinterpret_cast<__libcpp_beginthreadex_thunk_data *>(__data);
511  delete reinterpret_cast<__libcpp_beginthreadex_thunk_data *>(__data);
512  return reinterpret_cast<unsigned int>(data.__func(data.__arg));
513}
514
515int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
516                           void *__arg)
517{
518  auto *data = new __libcpp_beginthreadex_thunk_data;
519  data->__func = __func;
520  data->__arg = __arg;
521
522  *__t = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
523                                                 __libcpp_beginthreadex_thunk,
524                                                 data, 0, NULL));
525  if (*__t)
526    return 0;
527  return GetLastError();
528}
529
530__libcpp_thread_id __libcpp_thread_get_current_id()
531{
532  return GetCurrentThreadId();
533}
534
535__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
536{
537  return GetThreadId(*__t);
538}
539
540int __libcpp_thread_join(__libcpp_thread_t *__t)
541{
542  if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
543    return GetLastError();
544  if (!CloseHandle(*__t))
545    return GetLastError();
546  return 0;
547}
548
549int __libcpp_thread_detach(__libcpp_thread_t *__t)
550{
551  if (!CloseHandle(*__t))
552    return GetLastError();
553  return 0;
554}
555
556void __libcpp_thread_yield()
557{
558  SwitchToThread();
559}
560
561// Thread Local Storage
562int __libcpp_tls_create(__libcpp_tls_key* __key,
563                        void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
564{
565  *__key = FlsAlloc(__at_exit);
566  if (*__key == FLS_OUT_OF_INDEXES)
567    return GetLastError();
568  return 0;
569}
570
571void *__libcpp_tls_get(__libcpp_tls_key __key)
572{
573  return FlsGetValue(__key);
574}
575
576int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
577{
578  if (!FlsSetValue(__key, __p))
579    return GetLastError();
580  return 0;
581}
582
583#endif // _LIBCPP_HAS_THREAD_API_PTHREAD
584
585#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
586
587_LIBCPP_END_NAMESPACE_STD
588
589#endif // !_LIBCPP_HAS_NO_THREADS
590
591#endif // _LIBCPP_THREADING_SUPPORT
592