master
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the w64 mingw-runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include <assert.h>
12#include <errno.h>
13#include <stdint.h>
14#include <time.h>
15
16#define WIN32_LEAN_AND_MEAN
17#include <windows.h>
18
19#define WINPTHREAD_CLOCK_DECL WINPTHREAD_API
20
21/* public header files */
22#include "pthread_time.h"
23/* internal header files */
24#include "misc.h"
25
26#define POW10_7 10000000
27#define POW10_9 1000000000
28
29/* Number of 100ns-seconds between the beginning of the Windows epoch
30 * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970)
31 */
32#define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000)
33
34static WINPTHREADS_INLINE int lc_set_errno(int result)
35{
36 if (result != 0) {
37 errno = result;
38 return -1;
39 }
40 return 0;
41}
42
43/**
44 * Get the resolution of the specified clock clock_id and
45 * stores it in the struct timespec pointed to by res.
46 * @param clock_id The clock_id argument is the identifier of the particular
47 * clock on which to act. The following clocks are supported:
48 * <pre>
49 * CLOCK_REALTIME System-wide real-time clock. Setting this clock
50 * requires appropriate privileges.
51 * CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
52 * time since some unspecified starting point.
53 * CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
54 * CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
55 * </pre>
56 * @param res The pointer to a timespec structure to receive the time
57 * resolution.
58 * @return If the function succeeds, the return value is 0.
59 * If the function fails, the return value is -1,
60 * with errno set to indicate the error.
61 */
62static int __clock_getres(clockid_t clock_id, struct _timespec64 *res)
63{
64 clockid_t id = clock_id;
65
66 if (id == CLOCK_REALTIME && _pthread_get_system_time_best_as_file_time == GetSystemTimeAsFileTime)
67 id = CLOCK_REALTIME_COARSE; /* GetSystemTimePreciseAsFileTime() not available */
68
69 switch(id) {
70 case CLOCK_REALTIME:
71 case CLOCK_MONOTONIC:
72 {
73 LARGE_INTEGER pf;
74
75 if (QueryPerformanceFrequency(&pf) == 0)
76 return lc_set_errno(EINVAL);
77
78 res->tv_sec = 0;
79 res->tv_nsec = (int) ((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
80 if (res->tv_nsec < 1)
81 res->tv_nsec = 1;
82
83 return 0;
84 }
85
86 case CLOCK_REALTIME_COARSE:
87 case CLOCK_PROCESS_CPUTIME_ID:
88 case CLOCK_THREAD_CPUTIME_ID:
89 {
90 DWORD timeAdjustment, timeIncrement;
91 BOOL isTimeAdjustmentDisabled;
92
93 (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled);
94 res->tv_sec = 0;
95 res->tv_nsec = timeIncrement * 100;
96
97 return 0;
98 }
99 default:
100 break;
101 }
102
103 return lc_set_errno(EINVAL);
104}
105
106/**
107 * Get the time of the specified clock clock_id and stores it in the struct
108 * timespec pointed to by tp.
109 * @param clock_id The clock_id argument is the identifier of the particular
110 * clock on which to act. The following clocks are supported:
111 * <pre>
112 * CLOCK_REALTIME System-wide real-time clock. Setting this clock
113 * requires appropriate privileges.
114 * CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
115 * time since some unspecified starting point.
116 * CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
117 * CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
118 * </pre>
119 * @param tp The pointer to a timespec structure to receive the time.
120 * @return If the function succeeds, the return value is 0.
121 * If the function fails, the return value is -1,
122 * with errno set to indicate the error.
123 */
124static int __clock_gettime(clockid_t clock_id, struct _timespec64 *tp)
125{
126 unsigned __int64 t;
127 LARGE_INTEGER pf, pc;
128 union {
129 unsigned __int64 u64;
130 FILETIME ft;
131 } ct, et, kt, ut;
132
133 switch(clock_id) {
134 case CLOCK_REALTIME:
135 {
136 _pthread_get_system_time_best_as_file_time(&ct.ft);
137 t = ct.u64 - DELTA_EPOCH_IN_100NS;
138 tp->tv_sec = t / POW10_7;
139 tp->tv_nsec = ((int) (t % POW10_7)) * 100;
140
141 return 0;
142 }
143
144 case CLOCK_REALTIME_COARSE:
145 {
146 GetSystemTimeAsFileTime(&ct.ft);
147 t = ct.u64 - DELTA_EPOCH_IN_100NS;
148 tp->tv_sec = t / POW10_7;
149 tp->tv_nsec = ((int) (t % POW10_7)) * 100;
150
151 return 0;
152 }
153
154 case CLOCK_MONOTONIC:
155 {
156 if (QueryPerformanceFrequency(&pf) == 0)
157 return lc_set_errno(EINVAL);
158
159 if (QueryPerformanceCounter(&pc) == 0)
160 return lc_set_errno(EINVAL);
161
162 tp->tv_sec = pc.QuadPart / pf.QuadPart;
163 tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
164 if (tp->tv_nsec >= POW10_9) {
165 tp->tv_sec ++;
166 tp->tv_nsec -= POW10_9;
167 }
168
169 return 0;
170 }
171
172 case CLOCK_PROCESS_CPUTIME_ID:
173 {
174 if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
175 return lc_set_errno(EINVAL);
176 t = kt.u64 + ut.u64;
177 tp->tv_sec = t / POW10_7;
178 tp->tv_nsec = ((int) (t % POW10_7)) * 100;
179
180 return 0;
181 }
182
183 case CLOCK_THREAD_CPUTIME_ID:
184 {
185 if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
186 return lc_set_errno(EINVAL);
187 t = kt.u64 + ut.u64;
188 tp->tv_sec = t / POW10_7;
189 tp->tv_nsec = ((int) (t % POW10_7)) * 100;
190
191 return 0;
192 }
193
194 default:
195 break;
196 }
197
198 return lc_set_errno(EINVAL);
199}
200
201/**
202 * Sleep for the specified time.
203 * @param clock_id This argument should always be CLOCK_REALTIME (0).
204 * @param flags 0 for relative sleep interval, others for absolute waking up.
205 * @param request The desired sleep interval or absolute waking up time.
206 * @param remain The remain amount of time to sleep.
207 * The current implemention just ignore it.
208 * @return If the function succeeds, the return value is 0.
209 * If the function fails, the return value is -1,
210 * with errno set to indicate the error.
211 */
212static int __clock_nanosleep(clockid_t clock_id, int flags,
213 const struct _timespec64 *request,
214 struct _timespec64 *remain)
215{
216 struct _timespec64 tp;
217
218 if (clock_id != CLOCK_REALTIME)
219 return lc_set_errno(EINVAL);
220
221 if (flags == 0)
222 return nanosleep64(request, remain);
223
224 /* TIMER_ABSTIME = 1 */
225 __clock_gettime(CLOCK_REALTIME, &tp);
226
227 tp.tv_sec = request->tv_sec - tp.tv_sec;
228 tp.tv_nsec = request->tv_nsec - tp.tv_nsec;
229 if (tp.tv_nsec < 0) {
230 tp.tv_nsec += POW10_9;
231 tp.tv_sec --;
232 }
233
234 return nanosleep64(&tp, remain);
235}
236
237/**
238 * Set the time of the specified clock clock_id.
239 * @param clock_id This argument should always be CLOCK_REALTIME (0).
240 * @param tp The requested time.
241 * @return If the function succeeds, the return value is 0.
242 * If the function fails, the return value is -1,
243 * with errno set to indicate the error.
244 */
245static int __clock_settime(clockid_t clock_id, const struct _timespec64 *tp)
246{
247 SYSTEMTIME st;
248
249 union {
250 unsigned __int64 u64;
251 FILETIME ft;
252 } t;
253
254 if (clock_id != CLOCK_REALTIME)
255 return lc_set_errno(EINVAL);
256
257 t.u64 = tp->tv_sec * (__int64) POW10_7 + tp->tv_nsec / 100 + DELTA_EPOCH_IN_100NS;
258 if (FileTimeToSystemTime(&t.ft, &st) == 0)
259 return lc_set_errno(EINVAL);
260
261 if (SetSystemTime(&st) == 0)
262 return lc_set_errno(EPERM);
263
264 return 0;
265}
266
267/**
268 * Versions to use with 64-bit time_t (struct _timespec64)
269 */
270
271int clock_getres64 (clockid_t clock_id, struct _timespec64 *tp)
272{
273 return __clock_getres (clock_id, tp);
274}
275
276int clock_gettime64 (clockid_t clock_id, struct _timespec64 *tp)
277{
278 return __clock_gettime (clock_id, tp);
279}
280
281int clock_settime64 (clockid_t clock_id, const struct _timespec64 *tp)
282{
283 return __clock_settime (clock_id, tp);
284}
285
286int clock_nanosleep64 (clockid_t clock_id, int flags,
287 const struct _timespec64 *request, struct _timespec64 *remain)
288{
289 return __clock_nanosleep (clock_id, flags, request, remain);
290}
291
292/**
293 * Versions to use with 32-bit time_t (struct _timespec32)
294 */
295
296int clock_getres32 (clockid_t clock_id, struct _timespec32 *tp)
297{
298 struct _timespec64 tp64 = {0};
299
300 if (__clock_getres (clock_id, &tp64) == -1)
301 return -1;
302
303 tp->tv_sec = (__time32_t) tp64.tv_sec;
304 tp->tv_nsec = tp64.tv_nsec;
305
306 return 0;
307}
308
309int clock_gettime32 (clockid_t clock_id, struct _timespec32 *tp)
310{
311 struct _timespec64 tp64 = {0};
312
313 if (__clock_gettime (clock_id, &tp64) == -1)
314 return -1;
315
316 if (tp64.tv_sec > INT_MAX)
317 {
318 _set_errno (EOVERFLOW);
319 return -1;
320 }
321
322 tp->tv_sec = (__time32_t) tp64.tv_sec;
323 tp->tv_nsec = tp64.tv_nsec;
324
325 return 0;
326}
327
328int clock_settime32 (clockid_t clock_id, const struct _timespec32 *tp)
329{
330 struct _timespec64 tp64 = {.tv_sec = tp->tv_sec, .tv_nsec = tp->tv_nsec};
331 return __clock_settime (clock_id, &tp64);
332}
333
334int clock_nanosleep32 (clockid_t clock_id, int flags,
335 const struct _timespec32 *request, struct _timespec32 *remain)
336{
337 struct _timespec64 request64 = {
338 .tv_sec = request->tv_sec,
339 .tv_nsec = request->tv_nsec
340 };
341 struct _timespec64 remain64 = {0};
342
343 if (__clock_nanosleep (clock_id, flags, &request64, &remain64) == -1)
344 return -1;
345
346 assert (remain64.tv_sec <= INT_MAX);
347
348 if (remain != NULL) {
349 remain->tv_sec = (__time32_t)remain64.tv_sec;
350 remain->tv_nsec = remain64.tv_nsec;
351 }
352
353 return 0;
354}