xref: /freebsd-src/contrib/llvm-project/libcxx/include/__thread/support/c11.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric // -*- C++ -*-
2*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
3*0fca6ea1SDimitry Andric //
4*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*0fca6ea1SDimitry Andric //
8*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
9*0fca6ea1SDimitry Andric 
10*0fca6ea1SDimitry Andric #ifndef _LIBCPP___THREAD_SUPPORT_C11_H
11*0fca6ea1SDimitry Andric #define _LIBCPP___THREAD_SUPPORT_C11_H
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include <__chrono/convert_to_timespec.h>
14*0fca6ea1SDimitry Andric #include <__chrono/duration.h>
15*0fca6ea1SDimitry Andric #include <__config>
16*0fca6ea1SDimitry Andric #include <ctime>
17*0fca6ea1SDimitry Andric #include <errno.h>
18*0fca6ea1SDimitry Andric #include <threads.h>
19*0fca6ea1SDimitry Andric 
20*0fca6ea1SDimitry Andric #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
21*0fca6ea1SDimitry Andric #  pragma GCC system_header
22*0fca6ea1SDimitry Andric #endif
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric using __libcpp_timespec_t = ::timespec;
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric //
29*0fca6ea1SDimitry Andric // Mutex
30*0fca6ea1SDimitry Andric //
31*0fca6ea1SDimitry Andric typedef mtx_t __libcpp_mutex_t;
32*0fca6ea1SDimitry Andric // mtx_t is a struct so using {} for initialization is valid.
33*0fca6ea1SDimitry Andric #define _LIBCPP_MUTEX_INITIALIZER                                                                                      \
34*0fca6ea1SDimitry Andric   {}
35*0fca6ea1SDimitry Andric 
36*0fca6ea1SDimitry Andric typedef mtx_t __libcpp_recursive_mutex_t;
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) {
39*0fca6ea1SDimitry Andric   return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
40*0fca6ea1SDimitry Andric }
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
43*0fca6ea1SDimitry Andric __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) {
44*0fca6ea1SDimitry Andric   return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
45*0fca6ea1SDimitry Andric }
46*0fca6ea1SDimitry Andric 
47*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool
48*0fca6ea1SDimitry Andric __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) {
49*0fca6ea1SDimitry Andric   return mtx_trylock(__m) == thrd_success;
50*0fca6ea1SDimitry Andric }
51*0fca6ea1SDimitry Andric 
52*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
53*0fca6ea1SDimitry Andric __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) {
54*0fca6ea1SDimitry Andric   return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
55*0fca6ea1SDimitry Andric }
56*0fca6ea1SDimitry Andric 
57*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) {
58*0fca6ea1SDimitry Andric   mtx_destroy(__m);
59*0fca6ea1SDimitry Andric   return 0;
60*0fca6ea1SDimitry Andric }
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m) {
63*0fca6ea1SDimitry Andric   return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
64*0fca6ea1SDimitry Andric }
65*0fca6ea1SDimitry Andric 
66*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) {
67*0fca6ea1SDimitry Andric   return mtx_trylock(__m) == thrd_success;
68*0fca6ea1SDimitry Andric }
69*0fca6ea1SDimitry Andric 
70*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) {
71*0fca6ea1SDimitry Andric   return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
72*0fca6ea1SDimitry Andric }
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) {
75*0fca6ea1SDimitry Andric   mtx_destroy(__m);
76*0fca6ea1SDimitry Andric   return 0;
77*0fca6ea1SDimitry Andric }
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric //
80*0fca6ea1SDimitry Andric // Condition Variable
81*0fca6ea1SDimitry Andric //
82*0fca6ea1SDimitry Andric typedef cnd_t __libcpp_condvar_t;
83*0fca6ea1SDimitry Andric // cnd_t is a struct so using {} for initialization is valid.
84*0fca6ea1SDimitry Andric #define _LIBCPP_CONDVAR_INITIALIZER                                                                                    \
85*0fca6ea1SDimitry Andric   {}
86*0fca6ea1SDimitry Andric 
87*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) {
88*0fca6ea1SDimitry Andric   return cnd_signal(__cv) == thrd_success ? 0 : EINVAL;
89*0fca6ea1SDimitry Andric }
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) {
92*0fca6ea1SDimitry Andric   return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL;
93*0fca6ea1SDimitry Andric }
94*0fca6ea1SDimitry Andric 
95*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
96*0fca6ea1SDimitry Andric __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) {
97*0fca6ea1SDimitry Andric   return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
98*0fca6ea1SDimitry Andric }
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int
101*0fca6ea1SDimitry Andric __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts) {
102*0fca6ea1SDimitry Andric   int __ec = cnd_timedwait(__cv, __m, __ts);
103*0fca6ea1SDimitry Andric   return __ec == thrd_timedout ? ETIMEDOUT : __ec;
104*0fca6ea1SDimitry Andric }
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) {
107*0fca6ea1SDimitry Andric   cnd_destroy(__cv);
108*0fca6ea1SDimitry Andric   return 0;
109*0fca6ea1SDimitry Andric }
110*0fca6ea1SDimitry Andric 
111*0fca6ea1SDimitry Andric //
112*0fca6ea1SDimitry Andric // Execute once
113*0fca6ea1SDimitry Andric //
114*0fca6ea1SDimitry Andric typedef ::once_flag __libcpp_exec_once_flag;
115*0fca6ea1SDimitry Andric #define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT
116*0fca6ea1SDimitry Andric 
117*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_execute_once(__libcpp_exec_once_flag* flag, void (*init_routine)(void)) {
118*0fca6ea1SDimitry Andric   ::call_once(flag, init_routine);
119*0fca6ea1SDimitry Andric   return 0;
120*0fca6ea1SDimitry Andric }
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric //
123*0fca6ea1SDimitry Andric // Thread id
124*0fca6ea1SDimitry Andric //
125*0fca6ea1SDimitry Andric typedef thrd_t __libcpp_thread_id;
126*0fca6ea1SDimitry Andric 
127*0fca6ea1SDimitry Andric // Returns non-zero if the thread ids are equal, otherwise 0
128*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) {
129*0fca6ea1SDimitry Andric   return thrd_equal(t1, t2) != 0;
130*0fca6ea1SDimitry Andric }
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric // Returns non-zero if t1 < t2, otherwise 0
133*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) {
134*0fca6ea1SDimitry Andric   return t1 < t2;
135*0fca6ea1SDimitry Andric }
136*0fca6ea1SDimitry Andric 
137*0fca6ea1SDimitry Andric //
138*0fca6ea1SDimitry Andric // Thread
139*0fca6ea1SDimitry Andric //
140*0fca6ea1SDimitry Andric #define _LIBCPP_NULL_THREAD 0U
141*0fca6ea1SDimitry Andric 
142*0fca6ea1SDimitry Andric typedef thrd_t __libcpp_thread_t;
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) { return *__t; }
145*0fca6ea1SDimitry Andric 
146*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
147*0fca6ea1SDimitry Andric   return __libcpp_thread_get_id(__t) == 0;
148*0fca6ea1SDimitry Andric }
149*0fca6ea1SDimitry Andric 
150*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
151*0fca6ea1SDimitry Andric   int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg);
152*0fca6ea1SDimitry Andric   return __ec == thrd_nomem ? ENOMEM : __ec;
153*0fca6ea1SDimitry Andric }
154*0fca6ea1SDimitry Andric 
155*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_current_id() { return thrd_current(); }
156*0fca6ea1SDimitry Andric 
157*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_join(__libcpp_thread_t* __t) {
158*0fca6ea1SDimitry Andric   return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL;
159*0fca6ea1SDimitry Andric }
160*0fca6ea1SDimitry Andric 
161*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_detach(__libcpp_thread_t* __t) {
162*0fca6ea1SDimitry Andric   return thrd_detach(*__t) == thrd_success ? 0 : EINVAL;
163*0fca6ea1SDimitry Andric }
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void __libcpp_thread_yield() { thrd_yield(); }
166*0fca6ea1SDimitry Andric 
167*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
168*0fca6ea1SDimitry Andric   __libcpp_timespec_t __ts = std::__convert_to_timespec<__libcpp_timespec_t>(__ns);
169*0fca6ea1SDimitry Andric   thrd_sleep(&__ts, nullptr);
170*0fca6ea1SDimitry Andric }
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric //
173*0fca6ea1SDimitry Andric // Thread local storage
174*0fca6ea1SDimitry Andric //
175*0fca6ea1SDimitry Andric #define _LIBCPP_TLS_DESTRUCTOR_CC /* nothing */
176*0fca6ea1SDimitry Andric 
177*0fca6ea1SDimitry Andric typedef tss_t __libcpp_tls_key;
178*0fca6ea1SDimitry Andric 
179*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) {
180*0fca6ea1SDimitry Andric   return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
181*0fca6ea1SDimitry Andric }
182*0fca6ea1SDimitry Andric 
183*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_tls_get(__libcpp_tls_key __key) { return tss_get(__key); }
184*0fca6ea1SDimitry Andric 
185*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) {
186*0fca6ea1SDimitry Andric   return tss_set(__key, __p) == thrd_success ? 0 : EINVAL;
187*0fca6ea1SDimitry Andric }
188*0fca6ea1SDimitry Andric 
189*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD
190*0fca6ea1SDimitry Andric 
191*0fca6ea1SDimitry Andric #endif // _LIBCPP___THREAD_SUPPORT_C11_H
192