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 using namespace chrono; 250 // round-up to the nearest milisecond 251 milliseconds __ms = 252 duration_cast<milliseconds>(__ns + chrono::nanoseconds(999999)); 253 // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx) 254 Sleep(__ms.count()); 255 } 256 257 // Thread Local Storage 258 int __libcpp_tls_create(__libcpp_tls_key* __key, 259 void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*)) 260 { 261 DWORD index = FlsAlloc(__at_exit); 262 if (index == FLS_OUT_OF_INDEXES) 263 return GetLastError(); 264 *__key = index; 265 return 0; 266 } 267 268 void *__libcpp_tls_get(__libcpp_tls_key __key) 269 { 270 return FlsGetValue(__key); 271 } 272 273 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) 274 { 275 if (!FlsSetValue(__key, __p)) 276 return GetLastError(); 277 return 0; 278 } 279 280 // Semaphores 281 bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init) 282 { 283 *(PHANDLE)__sem = CreateSemaphoreEx(nullptr, __init, _LIBCPP_SEMAPHORE_MAX, 284 nullptr, 0, SEMAPHORE_ALL_ACCESS); 285 return *__sem != nullptr; 286 } 287 288 bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem) 289 { 290 CloseHandle(*(PHANDLE)__sem); 291 return true; 292 } 293 294 bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem) 295 { 296 return ReleaseSemaphore(*(PHANDLE)__sem, 1, nullptr); 297 } 298 299 bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem) 300 { 301 return WaitForSingleObjectEx(*(PHANDLE)__sem, INFINITE, false) == 302 WAIT_OBJECT_0; 303 } 304 305 bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, 306 chrono::nanoseconds const& __ns) 307 { 308 chrono::milliseconds __ms = std::chrono::ceil<chrono::milliseconds>(__ns); 309 return WaitForSingleObjectEx(*(PHANDLE)__sem, __ms.count(), false) == 310 WAIT_OBJECT_0; 311 } 312 313 _LIBCPP_END_NAMESPACE_STD 314