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 42 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) 43 { 44 InitializeCriticalSection((LPCRITICAL_SECTION)__m); 45 return 0; 46 } 47 48 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) 49 { 50 EnterCriticalSection((LPCRITICAL_SECTION)__m); 51 return 0; 52 } 53 54 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) 55 { 56 return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0; 57 } 58 59 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) 60 { 61 LeaveCriticalSection((LPCRITICAL_SECTION)__m); 62 return 0; 63 } 64 65 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) 66 { 67 DeleteCriticalSection((LPCRITICAL_SECTION)__m); 68 return 0; 69 } 70 71 int __libcpp_mutex_lock(__libcpp_mutex_t *__m) 72 { 73 AcquireSRWLockExclusive((PSRWLOCK)__m); 74 return 0; 75 } 76 77 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) 78 { 79 return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0; 80 } 81 82 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) 83 { 84 ReleaseSRWLockExclusive((PSRWLOCK)__m); 85 return 0; 86 } 87 88 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) 89 { 90 static_cast<void>(__m); 91 return 0; 92 } 93 94 // Condition Variable 95 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) 96 { 97 WakeConditionVariable((PCONDITION_VARIABLE)__cv); 98 return 0; 99 } 100 101 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) 102 { 103 WakeAllConditionVariable((PCONDITION_VARIABLE)__cv); 104 return 0; 105 } 106 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 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 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 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 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 163 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs, 164 __libcpp_thread_id __rhs) 165 { 166 return __lhs == __rhs; 167 } 168 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 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 192 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { 193 return *__t == 0; 194 } 195 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 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 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 231 int __libcpp_thread_detach(__libcpp_thread_t *__t) 232 { 233 if (!CloseHandle(*__t)) 234 return GetLastError(); 235 return 0; 236 } 237 238 void __libcpp_thread_yield() 239 { 240 SwitchToThread(); 241 } 242 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 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 264 void *__libcpp_tls_get(__libcpp_tls_key __key) 265 { 266 return FlsGetValue(__key); 267 } 268 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