1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <__thread/support/windows.h> 10 #include <chrono> 11 12 #define NOMINMAX 13 #define WIN32_LEAN_AND_MEAN 14 #include <windows.h> 15 #include <process.h> 16 #include <fibersapi.h> 17 18 _LIBCPP_BEGIN_NAMESPACE_STD 19 20 static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), ""); 21 static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), ""); 22 23 static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION), ""); 24 static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION), ""); 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 InitializeCriticalSection((LPCRITICAL_SECTION)__m); 44 return 0; 45 } 46 47 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) { 48 EnterCriticalSection((LPCRITICAL_SECTION)__m); 49 return 0; 50 } 51 52 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { 53 return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0; 54 } 55 56 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) { 57 LeaveCriticalSection((LPCRITICAL_SECTION)__m); 58 return 0; 59 } 60 61 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m) { 62 DeleteCriticalSection((LPCRITICAL_SECTION)__m); 63 return 0; 64 } 65 66 int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { 67 AcquireSRWLockExclusive((PSRWLOCK)__m); 68 return 0; 69 } 70 71 bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0; } 72 73 int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { 74 ReleaseSRWLockExclusive((PSRWLOCK)__m); 75 return 0; 76 } 77 78 int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) { 79 static_cast<void>(__m); 80 return 0; 81 } 82 83 // Condition Variable 84 int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) { 85 WakeConditionVariable((PCONDITION_VARIABLE)__cv); 86 return 0; 87 } 88 89 int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) { 90 WakeAllConditionVariable((PCONDITION_VARIABLE)__cv); 91 return 0; 92 } 93 94 int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) { 95 SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0); 96 return 0; 97 } 98 99 int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts) { 100 using namespace std::chrono; 101 102 auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec); 103 auto abstime = system_clock::time_point(duration_cast<system_clock::duration>(duration)); 104 auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now()); 105 106 if (!SleepConditionVariableSRW( 107 (PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, timeout_ms.count() > 0 ? timeout_ms.count() : 0, 0)) { 108 auto __ec = GetLastError(); 109 return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec; 110 } 111 return 0; 112 } 113 114 int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) { 115 static_cast<void>(__cv); 116 return 0; 117 } 118 119 // Execute Once 120 static inline _LIBCPP_HIDE_FROM_ABI BOOL CALLBACK 121 __libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter, PVOID* __context) { 122 static_cast<void>(__init_once); 123 static_cast<void>(__context); 124 125 void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter); 126 init_routine(); 127 return TRUE; 128 } 129 130 int __libcpp_execute_once(__libcpp_exec_once_flag* __flag, void (*__init_routine)(void)) { 131 if (!InitOnceExecuteOnce( 132 (PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk, reinterpret_cast<void*>(__init_routine), nullptr)) 133 return GetLastError(); 134 return 0; 135 } 136 137 // Thread ID 138 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs) { return __lhs == __rhs; } 139 140 bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs) { return __lhs < __rhs; } 141 142 // Thread 143 struct __libcpp_beginthreadex_thunk_data { 144 void* (*__func)(void*); 145 void* __arg; 146 }; 147 148 static inline _LIBCPP_HIDE_FROM_ABI unsigned WINAPI __libcpp_beginthreadex_thunk(void* __raw_data) { 149 auto* __data = static_cast<__libcpp_beginthreadex_thunk_data*>(__raw_data); 150 auto* __func = __data->__func; 151 void* __arg = __data->__arg; 152 delete __data; 153 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg))); 154 } 155 156 bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) { return *__t == 0; } 157 158 int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) { 159 auto* __data = new __libcpp_beginthreadex_thunk_data; 160 __data->__func = __func; 161 __data->__arg = __arg; 162 163 *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, __libcpp_beginthreadex_thunk, __data, 0, nullptr)); 164 165 if (*__t) 166 return 0; 167 return GetLastError(); 168 } 169 170 __libcpp_thread_id __libcpp_thread_get_current_id() { return GetCurrentThreadId(); } 171 172 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) { return GetThreadId(*__t); } 173 174 int __libcpp_thread_join(__libcpp_thread_t* __t) { 175 if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED) 176 return GetLastError(); 177 if (!CloseHandle(*__t)) 178 return GetLastError(); 179 return 0; 180 } 181 182 int __libcpp_thread_detach(__libcpp_thread_t* __t) { 183 if (!CloseHandle(*__t)) 184 return GetLastError(); 185 return 0; 186 } 187 188 void __libcpp_thread_yield() { SwitchToThread(); } 189 190 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) { 191 // round-up to the nearest millisecond 192 chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns); 193 // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx) 194 Sleep(__ms.count()); 195 } 196 197 // Thread Local Storage 198 int __libcpp_tls_create(__libcpp_tls_key* __key, void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*)) { 199 DWORD index = FlsAlloc(__at_exit); 200 if (index == FLS_OUT_OF_INDEXES) 201 return GetLastError(); 202 *__key = index; 203 return 0; 204 } 205 206 void* __libcpp_tls_get(__libcpp_tls_key __key) { return FlsGetValue(__key); } 207 208 int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) { 209 if (!FlsSetValue(__key, __p)) 210 return GetLastError(); 211 return 0; 212 } 213 214 _LIBCPP_END_NAMESPACE_STD 215