thread_win32.cpp (14311B)
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 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 19 static_assert(sizeof(__libcpp_mutex_t) == sizeof(CRITICAL_SECTION), ""); 20 static_assert(alignof(__libcpp_mutex_t) == alignof(CRITICAL_SECTION), ""); 21 #else 22 static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), ""); 23 static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), ""); 24 #endif 25 26 static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION), 27 ""); 28 static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION), 29 ""); 30 31 #ifndef _LIBCPP_MUTEXES_ARE_SHIT 32 static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), ""); 33 static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), ""); 34 #endif 35 36 #ifndef _LIBCPP_MUTEXES_ARE_SHIT 37 static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), ""); 38 static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), ""); 39 #endif 40 41 static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), ""); 42 static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), ""); 43 44 #ifndef _LIBCPP_MUTEXES_ARE_SHIT 45 static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), ""); 46 static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), ""); 47 #endif 48 49 static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), ""); 50 static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), ""); 51 52 // Mutex 53 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) 54 { 55 InitializeCriticalSection((LPCRITICAL_SECTION)__m); 56 return 0; 57 } 58 59 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) 60 { 61 EnterCriticalSection((LPCRITICAL_SECTION)__m); 62 return 0; 63 } 64 65 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) 66 { 67 return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0; 68 } 69 70 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) 71 { 72 LeaveCriticalSection((LPCRITICAL_SECTION)__m); 73 return 0; 74 } 75 76 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) 77 { 78 DeleteCriticalSection((LPCRITICAL_SECTION)__m); 79 return 0; 80 } 81 82 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 83 _LIBCPP_SAFE_STATIC static volatile long init_mutex = 0; 84 85 static void init_mtx_if_needed(__libcpp_mutex_t *__m) 86 { 87 if (**__m != (size_t) -1) return; 88 while (InterlockedCompareExchange(&init_mutex, 1, 0)) SwitchToThread(); 89 90 if (**__m == (size_t) -1) __libcpp_mutex_init(__m); 91 92 InterlockedExchange(&init_mutex, 0); 93 } 94 95 void __libcpp_mutex_init(__libcpp_mutex_t *__m) 96 { 97 **__m = 0; 98 InitializeCriticalSection((CRITICAL_SECTION*)__m); 99 } 100 #endif 101 102 int __libcpp_mutex_lock(__libcpp_mutex_t *__m) 103 { 104 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 105 init_mtx_if_needed(__m); 106 EnterCriticalSection((CRITICAL_SECTION*)__m); 107 #else 108 AcquireSRWLockExclusive((PSRWLOCK)__m); 109 #endif 110 return 0; 111 } 112 113 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) 114 { 115 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 116 init_mtx_if_needed(__m); 117 return TryEnterCriticalSection((CRITICAL_SECTION*)__m); 118 #else 119 return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0; 120 #endif 121 } 122 123 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) 124 { 125 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 126 LeaveCriticalSection((CRITICAL_SECTION*)__m); 127 #else 128 ReleaseSRWLockExclusive((PSRWLOCK)__m); 129 #endif 130 return 0; 131 } 132 133 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) 134 { 135 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 136 if (**__m != (size_t) -1) DeleteCriticalSection((CRITICAL_SECTION*)__m); 137 #endif 138 static_cast<void>(__m); 139 return 0; 140 } 141 142 // Condition Variable 143 // http://web.archive.org/web/20110721173110/https://www.cse.wustl.edu/~schmidt/win32-cv-1.html 144 // the second best solution, since the best is fucking complicated and nt4+ 145 // todo error handling 146 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 147 _LIBCPP_SAFE_STATIC static volatile long init_cv = 0; 148 149 static int init_cv_if_needed(__libcpp_condvar_t *__cv) 150 { 151 if (__cv->event != (size_t) -2) return 0; 152 while (InterlockedCompareExchange(&init_cv, 1, 0)) SwitchToThread(); 153 154 if (__cv->event != (size_t) -2) 155 { 156 // someone initialized it in the meantime 157 InterlockedExchange(&init_cv, 0); 158 return 0; 159 } 160 161 int res = __libcpp_condvar_init(__cv); 162 InterlockedExchange(&init_cv, 0); 163 return res; 164 } 165 166 int __libcpp_condvar_init(__libcpp_condvar_t *__cv) 167 { 168 __cv->waiter_count = __cv->release_count = __cv->generation_count = 0; 169 InitializeCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 170 __cv->event = (size_t) CreateEventW(nullptr, true, false, nullptr); 171 return __cv->event ? 0 : ENOMEM; 172 } 173 #endif 174 175 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) 176 { 177 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 178 int res = init_cv_if_needed(__cv); if (res != 0) return res; 179 EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 180 if (__cv->waiter_count > __cv->release_count) 181 { 182 SetEvent((HANDLE)__cv->event); 183 __cv->release_count++; 184 __cv->generation_count++; 185 } 186 LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 187 #else 188 WakeConditionVariable((PCONDITION_VARIABLE)__cv); 189 #endif 190 return 0; 191 } 192 193 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) 194 { 195 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 196 int res = init_cv_if_needed(__cv); if (res != 0) return res; 197 EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 198 if (__cv->waiter_count > 0) 199 { 200 SetEvent((HANDLE)__cv->event); 201 __cv->release_count = __cv->waiter_count; 202 __cv->generation_count++; 203 } 204 LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 205 #else 206 WakeAllConditionVariable((PCONDITION_VARIABLE)__cv); 207 #endif 208 return 0; 209 } 210 211 int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m) 212 { 213 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 214 int res = init_cv_if_needed(__cv); if (res != 0) return res; 215 #define WAIT_PRE \ 216 EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \ 217 __cv->waiter_count++; \ 218 unsigned my_gen = __cv->generation_count; \ 219 LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \ 220 __libcpp_mutex_unlock(__m) 221 WAIT_PRE; 222 223 while (true) 224 { 225 WaitForSingleObject((HANDLE)__cv->event, INFINITE); 226 #define WAIT_LOOP \ 227 EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \ 228 bool wait_done = __cv->release_count > 0 && __cv->generation_count != my_gen; \ 229 LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \ 230 if (wait_done) break 231 WAIT_LOOP; 232 } 233 234 #define WAIT_POST \ 235 __libcpp_mutex_lock(__m); \ 236 EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \ 237 --__cv->waiter_count; \ 238 bool last_waiter = --__cv->release_count == 0; \ 239 LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \ 240 if (last_waiter) ResetEvent((HANDLE)__cv->event) 241 WAIT_POST; 242 #else 243 SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0); 244 #endif 245 return 0; 246 } 247 248 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, 249 timespec *__ts) 250 { 251 using namespace _VSTD::chrono; 252 253 auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec); 254 auto abstime = 255 system_clock::time_point(duration_cast<system_clock::duration>(duration)); 256 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 257 auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now()).count(); 258 259 WAIT_PRE; 260 while (true) 261 { 262 switch (WaitForSingleObject((HANDLE)__cv->event, timeout_ms < 0 ? 0 : timeout_ms)) 263 { 264 case WAIT_OBJECT_0: break; 265 case WAIT_TIMEOUT: 266 EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 267 --__cv->waiter_count; 268 LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 269 return false; 270 default: abort(); 271 } 272 WAIT_LOOP; 273 timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now()).count(); 274 } 275 WAIT_POST; 276 #undef WAIT_PRE 277 #undef WAIT_LOOP 278 #undef WAIT_POST 279 #else 280 auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now()); 281 282 if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, 283 timeout_ms.count() > 0 ? timeout_ms.count() 284 : 0, 285 0)) 286 { 287 auto __ec = GetLastError(); 288 return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec; 289 } 290 #endif 291 return 0; 292 } 293 294 int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) 295 { 296 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 297 if (__cv->event == (size_t) -2) return 0; 298 CloseHandle((HANDLE) __cv->event); 299 DeleteCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); 300 #else 301 static_cast<void>(__cv); 302 #endif 303 return 0; 304 } 305 306 // Execute Once 307 static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK 308 __libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter, 309 PVOID *__context) 310 { 311 static_cast<void>(__init_once); 312 static_cast<void>(__context); 313 314 void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter); 315 init_routine(); 316 return TRUE; 317 } 318 319 // only used by libcxxabi 320 #ifndef _LIBCPP_MUTEXES_ARE_SHIT 321 int __libcpp_execute_once(__libcpp_exec_once_flag *__flag, 322 void (*__init_routine)(void)) 323 { 324 if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk, 325 reinterpret_cast<void *>(__init_routine), NULL)) 326 return GetLastError(); 327 return 0; 328 } 329 #endif 330 331 // Thread ID 332 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs, 333 __libcpp_thread_id __rhs) 334 { 335 return __lhs == __rhs; 336 } 337 338 bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs) 339 { 340 return __lhs < __rhs; 341 } 342 343 // Thread 344 struct __libcpp_beginthreadex_thunk_data 345 { 346 void *(*__func)(void *); 347 void *__arg; 348 }; 349 350 static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI 351 __libcpp_beginthreadex_thunk(void *__raw_data) 352 { 353 auto *__data = 354 static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data); 355 auto *__func = __data->__func; 356 void *__arg = __data->__arg; 357 delete __data; 358 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg))); 359 } 360 361 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 362 # define THREAD_HANDLE(__t) (__t)->handle 363 #else 364 # define THREAD_HANDLE(__t) (*(__t)) 365 #endif 366 367 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { 368 return THREAD_HANDLE(__t) == 0; 369 } 370 371 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), 372 void *__arg) 373 { 374 auto *__data = new __libcpp_beginthreadex_thunk_data; 375 __data->__func = __func; 376 __data->__arg = __arg; 377 378 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 379 __t->handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, 380 __libcpp_beginthreadex_thunk, 381 __data, 0, &__t->id)); 382 #else 383 *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, 384 __libcpp_beginthreadex_thunk, 385 __data, 0, nullptr)); 386 #endif 387 388 if (THREAD_HANDLE(__t)) 389 return 0; 390 return GetLastError(); 391 } 392 393 __libcpp_thread_id __libcpp_thread_get_current_id() 394 { 395 return GetCurrentThreadId(); 396 } 397 398 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) 399 { 400 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 401 return __t->id; 402 #else 403 return GetThreadId(*__t); 404 #endif 405 } 406 407 int __libcpp_thread_join(__libcpp_thread_t *__t) 408 { 409 if (WaitForSingleObjectEx(THREAD_HANDLE(__t), INFINITE, FALSE) == WAIT_FAILED) 410 return GetLastError(); 411 if (!CloseHandle(THREAD_HANDLE(__t))) 412 return GetLastError(); 413 return 0; 414 } 415 416 int __libcpp_thread_detach(__libcpp_thread_t *__t) 417 { 418 if (!CloseHandle(THREAD_HANDLE(__t))) 419 return GetLastError(); 420 return 0; 421 } 422 423 void __libcpp_thread_yield() 424 { 425 SwitchToThread(); 426 } 427 428 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) 429 { 430 using namespace chrono; 431 // round-up to the nearest milisecond 432 milliseconds __ms = 433 duration_cast<milliseconds>(__ns + chrono::nanoseconds(999999)); 434 // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx) 435 Sleep(__ms.count()); 436 } 437 438 // Thread Local Storage 439 440 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 441 namespace 442 { 443 struct Node 444 { 445 void(_LIBCPP_TLS_DESTRUCTOR_CC* fun)(void*); 446 Node* next; 447 DWORD idx; 448 }; 449 static Node* volatile root = nullptr; 450 451 struct DtorHolder 452 { 453 ~DtorHolder() 454 { 455 Node* n = (Node*) root; 456 while (n) 457 { 458 n->fun(TlsGetValue(n->idx)); 459 n = n->next; 460 } 461 } 462 }; 463 thread_local DtorHolder dtor_holder; 464 } 465 #endif 466 467 extern "C" int __cdecl __tlregdtor(_PVFV func); 468 int __libcpp_tls_create(__libcpp_tls_key* __key, 469 void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*)) 470 { 471 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 472 DWORD index = TlsAlloc(); 473 if (index == TLS_OUT_OF_INDEXES) 474 return GetLastError(); 475 *__key = index; 476 477 if (__at_exit) 478 { 479 Node* n = (Node*) malloc(sizeof(Node)); 480 if (!n) return ENOMEM; 481 n->fun = __at_exit; 482 n->idx = index; 483 n->next = root; 484 485 while (true) 486 { 487 Node* nroot = (Node*) InterlockedCompareExchangePointer((void* volatile*) &root, n, n->next); 488 if (nroot == n->next) break; 489 n->next = nroot; 490 } 491 } 492 #else 493 DWORD index = FlsAlloc(__at_exit); 494 if (index == FLS_OUT_OF_INDEXES) 495 return GetLastError(); 496 *__key = index; 497 #endif 498 return 0; 499 } 500 501 void *__libcpp_tls_get(__libcpp_tls_key __key) 502 { 503 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 504 return TlsGetValue(__key); 505 #else 506 return FlsGetValue(__key); 507 #endif 508 } 509 510 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) 511 { 512 #ifdef _LIBCPP_MUTEXES_ARE_SHIT 513 if (!TlsSetValue(__key, __p)) 514 #else 515 if (!FlsSetValue(__key, __p)) 516 #endif 517 return GetLastError(); 518 return 0; 519 } 520 521 _LIBCPP_END_NAMESPACE_STD