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}