blob: 1567042d8e2fc7d2be41cc64d854dd53826942eb [file] [log] [blame]
Peter Collingbourneac15ae62018-01-23 01:59:43 +00001// -*- 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
18static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
19static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
20
21static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
22 "");
23static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
24 "");
25
26static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
27static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
28
29static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
30static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
31
32static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
33static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
34
35static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
36static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
37
38static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
39static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
40
41// Mutex
42int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
43{
44 InitializeCriticalSection((LPCRITICAL_SECTION)__m);
45 return 0;
46}
47
48int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
49{
50 EnterCriticalSection((LPCRITICAL_SECTION)__m);
51 return 0;
52}
53
54bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
55{
56 return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
57}
58
59int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
60{
61 LeaveCriticalSection((LPCRITICAL_SECTION)__m);
62 return 0;
63}
64
65int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
66{
67 DeleteCriticalSection((LPCRITICAL_SECTION)__m);
68 return 0;
69}
70
71int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
72{
73 AcquireSRWLockExclusive((PSRWLOCK)__m);
74 return 0;
75}
76
77bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
78{
79 return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
80}
81
82int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
83{
84 ReleaseSRWLockExclusive((PSRWLOCK)__m);
85 return 0;
86}
87
88int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
89{
90 static_cast<void>(__m);
91 return 0;
92}
93
94// Condition Variable
95int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
96{
97 WakeConditionVariable((PCONDITION_VARIABLE)__cv);
98 return 0;
99}
100
101int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
102{
103 WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
104 return 0;
105}
106
107int __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
113int __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
134int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
135{
136 static_cast<void>(__cv);
137 return 0;
138}
139
140// Execute Once
Louis Dionnedc7200b2018-07-11 23:14:33 +0000141static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
Peter Collingbourneac15ae62018-01-23 01:59:43 +0000142__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
153int __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
163bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
164 __libcpp_thread_id __rhs)
165{
166 return __lhs == __rhs;
167}
168
169bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
170{
171 return __lhs < __rhs;
172}
173
174// Thread
175struct __libcpp_beginthreadex_thunk_data
176{
177 void *(*__func)(void *);
178 void *__arg;
179};
180
Louis Dionnedc7200b2018-07-11 23:14:33 +0000181static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
Peter Collingbourneac15ae62018-01-23 01:59:43 +0000182__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
192bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
193 return *__t == 0;
194}
195
196int __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
212__libcpp_thread_id __libcpp_thread_get_current_id()
213{
214 return GetCurrentThreadId();
215}
216
217__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
218{
219 return GetThreadId(*__t);
220}
221
222int __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
231int __libcpp_thread_detach(__libcpp_thread_t *__t)
232{
233 if (!CloseHandle(*__t))
234 return GetLastError();
235 return 0;
236}
237
238void __libcpp_thread_yield()
239{
240 SwitchToThread();
241}
242
243void __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
254int __libcpp_tls_create(__libcpp_tls_key* __key,
255 void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
256{
Martin Storsjoc89c9c72018-07-25 18:24:23 +0000257 DWORD index = FlsAlloc(__at_exit);
258 if (index == FLS_OUT_OF_INDEXES)
Peter Collingbourneac15ae62018-01-23 01:59:43 +0000259 return GetLastError();
Martin Storsjoc89c9c72018-07-25 18:24:23 +0000260 *__key = index;
Peter Collingbourneac15ae62018-01-23 01:59:43 +0000261 return 0;
262}
263
264void *__libcpp_tls_get(__libcpp_tls_key __key)
265{
266 return FlsGetValue(__key);
267}
268
269int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
270{
271 if (!FlsSetValue(__key, __p))
272 return GetLastError();
273 return 0;
274}
275
276_LIBCPP_END_NAMESPACE_STD