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 46 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) 47 { 48 InitializeCriticalSection((LPCRITICAL_SECTION)__m); 49 return 0; 50 } 51 52 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) 53 { 54 EnterCriticalSection((LPCRITICAL_SECTION)__m); 55 return 0; 56 } 57 58 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) 59 { 60 return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0; 61 } 62 63 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) 64 { 65 LeaveCriticalSection((LPCRITICAL_SECTION)__m); 66 return 0; 67 } 68 69 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) 70 { 71 DeleteCriticalSection((LPCRITICAL_SECTION)__m); 72 return 0; 73 } 74 75 int __libcpp_mutex_lock(__libcpp_mutex_t *__m) 76 { 77 AcquireSRWLockExclusive((PSRWLOCK)__m); 78 return 0; 79 } 80 81 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) 82 { 83 return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0; 84 } 85 86 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) 87 { 88 ReleaseSRWLockExclusive((PSRWLOCK)__m); 89 return 0; 90 } 91 92 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) 93 { 94 static_cast<void>(__m); 95 return 0; 96 } 97 98 // Condition Variable 99 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) 100 { 101 WakeConditionVariable((PCONDITION_VARIABLE)__cv); 102 return 0; 103 } 104 105 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) 106 { 107 WakeAllConditionVariable((PCONDITION_VARIABLE)__cv); 108 return 0; 109 } 110 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 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 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 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 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 167 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs, 168 __libcpp_thread_id __rhs) 169 { 170 return __lhs == __rhs; 171 } 172 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 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 196 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { 197 return *__t == 0; 198 } 199 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 216 __libcpp_thread_id __libcpp_thread_get_current_id() 217 { 218 return GetCurrentThreadId(); 219 } 220 221 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) 222 { 223 return GetThreadId(*__t); 224 } 225 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 235 int __libcpp_thread_detach(__libcpp_thread_t *__t) 236 { 237 if (!CloseHandle(*__t)) 238 return GetLastError(); 239 return 0; 240 } 241 242 void __libcpp_thread_yield() 243 { 244 SwitchToThread(); 245 } 246 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 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 266 void *__libcpp_tls_get(__libcpp_tls_key __key) 267 { 268 return FlsGetValue(__key); 269 } 270 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 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 286 bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem) 287 { 288 CloseHandle(*(PHANDLE)__sem); 289 return true; 290 } 291 292 bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem) 293 { 294 return ReleaseSemaphore(*(PHANDLE)__sem, 1, nullptr); 295 } 296 297 bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem) 298 { 299 return WaitForSingleObjectEx(*(PHANDLE)__sem, INFINITE, false) == 300 WAIT_OBJECT_0; 301 } 302 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