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