| 1 | /* |
| 2 | Copyright (c) 2011-2016 mingw-w64 project |
| 3 | |
| 4 | Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | copy of this software and associated documentation files (the "Software"), |
| 6 | to deal in the Software without restriction, including without limitation |
| 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | and/or sell copies of the Software, and to permit persons to whom the |
| 9 | Software is furnished to do so, subject to the following conditions: |
| 10 | |
| 11 | The above copyright notice and this permission notice shall be included in |
| 12 | all copies or substantial portions of the Software. |
| 13 | |
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 20 | DEALINGS IN THE SOFTWARE. |
| 21 | */ |
| 22 | |
| 23 | #ifdef HAVE_CONFIG_H |
| 24 | #include "config.h" |
| 25 | #endif |
| 26 | |
| 27 | #define WIN32_LEAN_AND_MEAN |
| 28 | #include <windows.h> |
| 29 | |
| 30 | /* public header files */ |
| 31 | #include "pthread.h" |
| 32 | /* internal header files */ |
| 33 | #include "misc.h" |
| 34 | |
| 35 | void (WINAPI *_pthread_get_system_time_best_as_file_time) (LPFILETIME) = NULL; |
| 36 | static ULONGLONG (WINAPI *_pthread_get_tick_count_64) (VOID); |
| 37 | HRESULT (WINAPI *_pthread_set_thread_description) (HANDLE, PCWSTR) = NULL; |
| 38 | BOOL (WINAPI *_pthread_get_handle_information) (HANDLE, LPDWORD) = NULL; |
| 39 | |
| 40 | #if defined(__GNUC__) || defined(__clang__) |
| 41 | #if __GNUC__ >= 9 && !defined(__clang__) |
| 42 | #pragma GCC diagnostic push |
| 43 | #pragma GCC diagnostic ignored "-Wprio-ctor-dtor" |
| 44 | #endif |
| 45 | __attribute__((constructor(0))) |
| 46 | #endif |
| 47 | static void winpthreads_init(void) |
| 48 | { |
| 49 | HMODULE mod = GetModuleHandleA("kernel32.dll"); |
| 50 | if (mod) |
| 51 | { |
| 52 | _pthread_get_handle_information = |
| 53 | (BOOL (WINAPI *)(HANDLE, LPDWORD))(void*) GetProcAddress(mod, "GetHandleInformation"); |
| 54 | |
| 55 | _pthread_get_tick_count_64 = |
| 56 | (ULONGLONG (WINAPI *)(VOID))(void*) GetProcAddress(mod, "GetTickCount64"); |
| 57 | |
| 58 | _pthread_set_thread_description = |
| 59 | (HRESULT (WINAPI *)(HANDLE, PCWSTR))(void*) GetProcAddress(mod, "SetThreadDescription"); |
| 60 | |
| 61 | /* <1us precision on Windows 10 */ |
| 62 | _pthread_get_system_time_best_as_file_time = |
| 63 | (void (WINAPI *)(LPFILETIME))(void*) GetProcAddress(mod, "GetSystemTimePreciseAsFileTime"); |
| 64 | } |
| 65 | |
| 66 | if (!_pthread_get_system_time_best_as_file_time) |
| 67 | /* >15ms precision on Windows 10 */ |
| 68 | _pthread_get_system_time_best_as_file_time = GetSystemTimeAsFileTime; |
| 69 | |
| 70 | /* Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016, |
| 71 | * Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in |
| 72 | * kernelbase.dll. So, load it from there for maximum coverage. |
| 73 | */ |
| 74 | if (!_pthread_set_thread_description) |
| 75 | { |
| 76 | mod = GetModuleHandleA("kernelbase.dll"); |
| 77 | if (mod) |
| 78 | { |
| 79 | _pthread_set_thread_description = |
| 80 | (HRESULT (WINAPI *)(HANDLE, PCWSTR))(void*) GetProcAddress(mod, "SetThreadDescription"); |
| 81 | } |
| 82 | } |
| 83 | } |
| 84 | #if defined(__GNUC__) && __GNUC__ >= 9 && !defined(__clang__) |
| 85 | #pragma GCC diagnostic pop |
| 86 | #endif |
| 87 | |
| 88 | #if defined(_MSC_VER) && !defined(__clang__) |
| 89 | /* Force a reference to __xc_t to prevent whole program optimization |
| 90 | * from discarding the variable. */ |
| 91 | |
| 92 | /* On x86, symbols are prefixed with an underscore. */ |
| 93 | # if defined(_M_IX86) |
| 94 | # pragma comment(linker, "/include:___xc_t") |
| 95 | # else |
| 96 | # pragma comment(linker, "/include:__xc_t") |
| 97 | # endif |
| 98 | |
| 99 | #pragma section(".CRT$XCT", long, read) |
| 100 | __declspec(allocate(".CRT$XCT")) |
| 101 | extern const _PVFV __xc_t; |
| 102 | const _PVFV __xc_t = winpthreads_init; |
| 103 | #endif |
| 104 | |
| 105 | unsigned long long _pthread_time_in_ms(void) |
| 106 | { |
| 107 | FILETIME ft; |
| 108 | |
| 109 | GetSystemTimeAsFileTime(&ft); |
| 110 | return (((unsigned long long)ft.dwHighDateTime << 32) + ft.dwLowDateTime |
| 111 | - 0x19DB1DED53E8000ULL) / 10000ULL; |
| 112 | } |
| 113 | |
| 114 | unsigned long long _pthread_time_in_ms_from_timespec(const struct _timespec64 *ts) |
| 115 | { |
| 116 | unsigned long long t = (unsigned long long) ts->tv_sec * 1000LL; |
| 117 | /* The +999999 is here to ensure that the division always rounds up */ |
| 118 | t += (unsigned long long) (ts->tv_nsec + 999999) / 1000000; |
| 119 | |
| 120 | return t; |
| 121 | } |
| 122 | |
| 123 | unsigned long long _pthread_rel_time_in_ms(const struct _timespec64 *ts) |
| 124 | { |
| 125 | unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts); |
| 126 | unsigned long long t2 = _pthread_time_in_ms(); |
| 127 | |
| 128 | /* Prevent underflow */ |
| 129 | if (t1 < t2) return 0; |
| 130 | return t1 - t2; |
| 131 | } |
| 132 | |
| 133 | static unsigned long long |
| 134 | _pthread_get_tick_count (long long *frequency) |
| 135 | { |
| 136 | if (_pthread_get_tick_count_64 != NULL) |
| 137 | return _pthread_get_tick_count_64 (); |
| 138 | |
| 139 | LARGE_INTEGER freq, timestamp; |
| 140 | |
| 141 | if (*frequency == 0) |
| 142 | { |
| 143 | if (QueryPerformanceFrequency (&freq)) |
| 144 | *frequency = freq.QuadPart; |
| 145 | else |
| 146 | *frequency = -1; |
| 147 | } |
| 148 | |
| 149 | if (*frequency > 0 && QueryPerformanceCounter (&timestamp)) |
| 150 | return timestamp.QuadPart / (*frequency / 1000); |
| 151 | |
| 152 | /* Fallback */ |
| 153 | return GetTickCount (); |
| 154 | } |
| 155 | |
| 156 | /* A wrapper around WaitForSingleObject() that ensures that |
| 157 | * the wait function does not time out before the time |
| 158 | * actually runs out. This is needed because WaitForSingleObject() |
| 159 | * might have poor accuracy, returning earlier than expected. |
| 160 | * On the other hand, returning a bit *later* than expected |
| 161 | * is acceptable in a preemptive multitasking environment. |
| 162 | */ |
| 163 | unsigned long |
| 164 | _pthread_wait_for_single_object (void *handle, unsigned long timeout) |
| 165 | { |
| 166 | DWORD result; |
| 167 | unsigned long long start_time, end_time; |
| 168 | unsigned long wait_time; |
| 169 | long long frequency = 0; |
| 170 | |
| 171 | if (timeout == INFINITE || timeout == 0) |
| 172 | return WaitForSingleObject ((HANDLE) handle, (DWORD) timeout); |
| 173 | |
| 174 | start_time = _pthread_get_tick_count (&frequency); |
| 175 | end_time = start_time + timeout; |
| 176 | wait_time = timeout; |
| 177 | |
| 178 | do |
| 179 | { |
| 180 | unsigned long long current_time; |
| 181 | |
| 182 | result = WaitForSingleObject ((HANDLE) handle, (DWORD) wait_time); |
| 183 | if (result != WAIT_TIMEOUT) |
| 184 | break; |
| 185 | |
| 186 | current_time = _pthread_get_tick_count (&frequency); |
| 187 | if (current_time >= end_time) |
| 188 | break; |
| 189 | |
| 190 | wait_time = (DWORD) (end_time - current_time); |
| 191 | } while (TRUE); |
| 192 | |
| 193 | return result; |
| 194 | } |
| 195 | |
| 196 | /* A wrapper around WaitForMultipleObjects() that ensures that |
| 197 | * the wait function does not time out before the time |
| 198 | * actually runs out. This is needed because WaitForMultipleObjects() |
| 199 | * might have poor accuracy, returning earlier than expected. |
| 200 | * On the other hand, returning a bit *later* than expected |
| 201 | * is acceptable in a preemptive multitasking environment. |
| 202 | */ |
| 203 | unsigned long |
| 204 | _pthread_wait_for_multiple_objects (unsigned long count, void **handles, unsigned int all, unsigned long timeout) |
| 205 | { |
| 206 | DWORD result; |
| 207 | unsigned long long start_time, end_time; |
| 208 | unsigned long wait_time; |
| 209 | long long frequency = 0; |
| 210 | |
| 211 | if (timeout == INFINITE || timeout == 0) |
| 212 | return WaitForMultipleObjects ((DWORD) count, (HANDLE *) handles, all, (DWORD) timeout); |
| 213 | |
| 214 | start_time = _pthread_get_tick_count (&frequency); |
| 215 | end_time = start_time + timeout; |
| 216 | wait_time = timeout; |
| 217 | |
| 218 | do |
| 219 | { |
| 220 | unsigned long long current_time; |
| 221 | |
| 222 | result = WaitForMultipleObjects ((DWORD) count, (HANDLE *) handles, all, (DWORD) wait_time); |
| 223 | if (result != WAIT_TIMEOUT) |
| 224 | break; |
| 225 | |
| 226 | current_time = _pthread_get_tick_count (&frequency); |
| 227 | if (current_time >= end_time) |
| 228 | break; |
| 229 | |
| 230 | wait_time = (DWORD) (end_time - current_time); |
| 231 | } while (TRUE); |
| 232 | |
| 233 | return result; |
| 234 | } |