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 #include <__threading_support>
11 #define NOMINMAX
12 #define WIN32_LEAN_AND_MEAN
13 #include <windows.h>
14 #include <process.h>
15 #include <fibersapi.h>
16 
17 _LIBCPP_BEGIN_NAMESPACE_STD
18 
19 static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
20 static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
21 
22 static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
23               "");
24 static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
25               "");
26 
27 static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
28 static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
29 
30 static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
31 static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
32 
33 static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
34 static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
35 
36 static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
37 static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
38 
39 static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
40 static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
41 
42 static_assert(sizeof(__libcpp_semaphore_t) == sizeof(HANDLE), "");
43 static_assert(alignof(__libcpp_semaphore_t) == alignof(HANDLE), "");
44 
45 // Mutex
__libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t * __m)46 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
47 {
48   InitializeCriticalSection((LPCRITICAL_SECTION)__m);
49   return 0;
50 }
51 
__libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t * __m)52 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
53 {
54   EnterCriticalSection((LPCRITICAL_SECTION)__m);
55   return 0;
56 }
57 
__libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t * __m)58 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
59 {
60   return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
61 }
62 
__libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t * __m)63 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
64 {
65   LeaveCriticalSection((LPCRITICAL_SECTION)__m);
66   return 0;
67 }
68 
__libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t * __m)69 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
70 {
71   DeleteCriticalSection((LPCRITICAL_SECTION)__m);
72   return 0;
73 }
74 
__libcpp_mutex_lock(__libcpp_mutex_t * __m)75 int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
76 {
77   AcquireSRWLockExclusive((PSRWLOCK)__m);
78   return 0;
79 }
80 
__libcpp_mutex_trylock(__libcpp_mutex_t * __m)81 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
82 {
83   return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
84 }
85 
__libcpp_mutex_unlock(__libcpp_mutex_t * __m)86 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
87 {
88   ReleaseSRWLockExclusive((PSRWLOCK)__m);
89   return 0;
90 }
91 
__libcpp_mutex_destroy(__libcpp_mutex_t * __m)92 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
93 {
94   static_cast<void>(__m);
95   return 0;
96 }
97 
98 // Condition Variable
__libcpp_condvar_signal(__libcpp_condvar_t * __cv)99 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
100 {
101   WakeConditionVariable((PCONDITION_VARIABLE)__cv);
102   return 0;
103 }
104 
__libcpp_condvar_broadcast(__libcpp_condvar_t * __cv)105 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
106 {
107   WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
108   return 0;
109 }
110 
__libcpp_condvar_wait(__libcpp_condvar_t * __cv,__libcpp_mutex_t * __m)111 int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
112 {
113   SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0);
114   return 0;
115 }
116 
__libcpp_condvar_timedwait(__libcpp_condvar_t * __cv,__libcpp_mutex_t * __m,__libcpp_timespec_t * __ts)117 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
118                                __libcpp_timespec_t *__ts)
119 {
120   using namespace _VSTD::chrono;
121 
122   auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
123   auto abstime =
124       system_clock::time_point(duration_cast<system_clock::duration>(duration));
125   auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
126 
127   if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m,
128                                  timeout_ms.count() > 0 ? timeout_ms.count()
129                                                         : 0,
130                                  0))
131     {
132       auto __ec = GetLastError();
133       return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec;
134     }
135   return 0;
136 }
137 
__libcpp_condvar_destroy(__libcpp_condvar_t * __cv)138 int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
139 {
140   static_cast<void>(__cv);
141   return 0;
142 }
143 
144 // Execute Once
145 static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once,PVOID __parameter,PVOID * __context)146 __libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
147                                       PVOID *__context)
148 {
149   static_cast<void>(__init_once);
150   static_cast<void>(__context);
151 
152   void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
153   init_routine();
154   return TRUE;
155 }
156 
__libcpp_execute_once(__libcpp_exec_once_flag * __flag,void (* __init_routine)(void))157 int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
158                           void (*__init_routine)(void))
159 {
160   if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk,
161                            reinterpret_cast<void *>(__init_routine), NULL))
162     return GetLastError();
163   return 0;
164 }
165 
166 // Thread ID
__libcpp_thread_id_equal(__libcpp_thread_id __lhs,__libcpp_thread_id __rhs)167 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
168                               __libcpp_thread_id __rhs)
169 {
170   return __lhs == __rhs;
171 }
172 
__libcpp_thread_id_less(__libcpp_thread_id __lhs,__libcpp_thread_id __rhs)173 bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
174 {
175   return __lhs < __rhs;
176 }
177 
178 // Thread
179 struct __libcpp_beginthreadex_thunk_data
180 {
181   void *(*__func)(void *);
182   void *__arg;
183 };
184 
185 static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
__libcpp_beginthreadex_thunk(void * __raw_data)186 __libcpp_beginthreadex_thunk(void *__raw_data)
187 {
188   auto *__data =
189       static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
190   auto *__func = __data->__func;
191   void *__arg = __data->__arg;
192   delete __data;
193   return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
194 }
195 
__libcpp_thread_isnull(const __libcpp_thread_t * __t)196 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
197   return *__t == 0;
198 }
199 
__libcpp_thread_create(__libcpp_thread_t * __t,void * (* __func)(void *),void * __arg)200 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
201                            void *__arg)
202 {
203   auto *__data = new __libcpp_beginthreadex_thunk_data;
204   __data->__func = __func;
205   __data->__arg = __arg;
206 
207   *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
208                                                  __libcpp_beginthreadex_thunk,
209                                                  __data, 0, nullptr));
210 
211   if (*__t)
212     return 0;
213   return GetLastError();
214 }
215 
__libcpp_thread_get_current_id()216 __libcpp_thread_id __libcpp_thread_get_current_id()
217 {
218   return GetCurrentThreadId();
219 }
220 
__libcpp_thread_get_id(const __libcpp_thread_t * __t)221 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
222 {
223   return GetThreadId(*__t);
224 }
225 
__libcpp_thread_join(__libcpp_thread_t * __t)226 int __libcpp_thread_join(__libcpp_thread_t *__t)
227 {
228   if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
229     return GetLastError();
230   if (!CloseHandle(*__t))
231     return GetLastError();
232   return 0;
233 }
234 
__libcpp_thread_detach(__libcpp_thread_t * __t)235 int __libcpp_thread_detach(__libcpp_thread_t *__t)
236 {
237   if (!CloseHandle(*__t))
238     return GetLastError();
239   return 0;
240 }
241 
__libcpp_thread_yield()242 void __libcpp_thread_yield()
243 {
244   SwitchToThread();
245 }
246 
__libcpp_thread_sleep_for(const chrono::nanoseconds & __ns)247 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
248 {
249   // round-up to the nearest millisecond
250   chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns);
251   // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
252   Sleep(__ms.count());
253 }
254 
255 // Thread Local Storage
__libcpp_tls_create(__libcpp_tls_key * __key,void (_LIBCPP_TLS_DESTRUCTOR_CC * __at_exit)(void *))256 int __libcpp_tls_create(__libcpp_tls_key* __key,
257                         void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
258 {
259   DWORD index = FlsAlloc(__at_exit);
260   if (index == FLS_OUT_OF_INDEXES)
261     return GetLastError();
262   *__key = index;
263   return 0;
264 }
265 
__libcpp_tls_get(__libcpp_tls_key __key)266 void *__libcpp_tls_get(__libcpp_tls_key __key)
267 {
268   return FlsGetValue(__key);
269 }
270 
__libcpp_tls_set(__libcpp_tls_key __key,void * __p)271 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
272 {
273   if (!FlsSetValue(__key, __p))
274     return GetLastError();
275   return 0;
276 }
277 
278 // Semaphores
__libcpp_semaphore_init(__libcpp_semaphore_t * __sem,int __init)279 bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init)
280 {
281   *(PHANDLE)__sem = CreateSemaphoreEx(nullptr, __init, _LIBCPP_SEMAPHORE_MAX,
282                                       nullptr, 0, SEMAPHORE_ALL_ACCESS);
283   return *__sem != nullptr;
284 }
285 
__libcpp_semaphore_destroy(__libcpp_semaphore_t * __sem)286 bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem)
287 {
288   CloseHandle(*(PHANDLE)__sem);
289   return true;
290 }
291 
__libcpp_semaphore_post(__libcpp_semaphore_t * __sem)292 bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem)
293 {
294   return ReleaseSemaphore(*(PHANDLE)__sem, 1, nullptr);
295 }
296 
__libcpp_semaphore_wait(__libcpp_semaphore_t * __sem)297 bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem)
298 {
299   return WaitForSingleObjectEx(*(PHANDLE)__sem, INFINITE, false) ==
300          WAIT_OBJECT_0;
301 }
302 
__libcpp_semaphore_wait_timed(__libcpp_semaphore_t * __sem,chrono::nanoseconds const & __ns)303 bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem,
304                                    chrono::nanoseconds const& __ns)
305 {
306   chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns);
307   return WaitForSingleObjectEx(*(PHANDLE)__sem, __ms.count(), false) ==
308          WAIT_OBJECT_0;
309 }
310 
311 _LIBCPP_END_NAMESPACE_STD
312