• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_INLINE_VISIBILITY 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_INLINE_VISIBILITY 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   DWORD index = FlsAlloc(__at_exit);
258   if (index == FLS_OUT_OF_INDEXES)
259     return GetLastError();
260   *__key = index;
261   return 0;
262 }
263 
__libcpp_tls_get(__libcpp_tls_key __key)264 void *__libcpp_tls_get(__libcpp_tls_key __key)
265 {
266   return FlsGetValue(__key);
267 }
268 
__libcpp_tls_set(__libcpp_tls_key __key,void * __p)269 int __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
277