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