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
35void (WINAPI *_pthread_get_system_time_best_as_file_time) (LPFILETIME) = NULL;
36static ULONGLONG (WINAPI *_pthread_get_tick_count_64) (VOID);
37HRESULT (WINAPI *_pthread_set_thread_description) (HANDLE, PCWSTR) = NULL;
38BOOL (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
47static 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"))
101extern const _PVFV __xc_t;
102const _PVFV __xc_t = winpthreads_init;
103#endif
104
105unsigned 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
114unsigned 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
123unsigned 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
133static 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 */
163unsigned 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 */
203unsigned 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}