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 <time.h>
 14
 15#define WIN32_LEAN_AND_MEAN
 16#include <windows.h>
 17
 18#define WINPTHREAD_NANOSLEEP_DECL WINPTHREAD_API
 19
 20/* public header files */
 21#include "pthread.h"
 22#include "pthread_time.h"
 23/* internal header files */
 24#include "thread.h"
 25
 26#define POW10_3                 1000
 27#define POW10_4                 10000
 28#define POW10_6                 1000000
 29#define POW10_9                 1000000000
 30#define MAX_SLEEP_IN_MS         4294967294UL
 31
 32/**
 33 * Sleep for the specified time.
 34 * @param  request The desired amount of time to sleep.
 35 * @param  remain The remain amount of time to sleep.
 36 * @return If the function succeeds, the return value is 0.
 37 *         If the function fails, the return value is -1,
 38 *         with errno set to indicate the error.
 39 */
 40static int __nanosleep(const struct _timespec64 *request, struct _timespec64 *remain)
 41{
 42    unsigned long ms, rc = 0;
 43    unsigned __int64 u64, want, real;
 44
 45    union {
 46        unsigned __int64 ns100;
 47        FILETIME ft;
 48    }  _start, _end;
 49
 50    if (request->tv_sec < 0 || request->tv_nsec < 0 || request->tv_nsec >= POW10_9) {
 51        errno = EINVAL;
 52        return -1;
 53    }
 54
 55    if (remain != NULL) GetSystemTimeAsFileTime(&_start.ft);
 56
 57    want = u64 = request->tv_sec * POW10_3 + request->tv_nsec / POW10_6;
 58    while (u64 > 0 && rc == 0) {
 59        if (u64 >= MAX_SLEEP_IN_MS) ms = MAX_SLEEP_IN_MS;
 60        else ms = (unsigned long) u64;
 61
 62        u64 -= ms;
 63        rc = _pthread_delay_np_ms(ms);
 64    }
 65
 66    if (rc != 0) { /* WAIT_IO_COMPLETION (192) */
 67        if (remain != NULL) {
 68            GetSystemTimeAsFileTime(&_end.ft);
 69            real = (_end.ns100 - _start.ns100) / POW10_4;
 70
 71            if (real >= want) u64 = 0;
 72            else u64 = want - real;
 73
 74            remain->tv_sec = u64 / POW10_3;
 75            remain->tv_nsec = (long) (u64 % POW10_3) * POW10_6;
 76        }
 77
 78        errno = EINTR;
 79        return -1;
 80    }
 81
 82    return 0;
 83}
 84
 85int nanosleep64(const struct _timespec64 *request, struct _timespec64 *remain)
 86{
 87    return __nanosleep (request, remain);
 88}
 89
 90int nanosleep32(const struct _timespec32 *request, struct _timespec32 *remain)
 91{
 92    struct _timespec64 request64 = {
 93        .tv_sec = request->tv_sec,
 94        .tv_nsec = request->tv_nsec
 95    };
 96    struct _timespec64 remain64 = {0};
 97
 98    if (__nanosleep (&request64, &remain64) == -1)
 99        return -1;
100
101    assert (remain64.tv_sec <= INT_MAX);
102
103    if (remain != NULL) {
104        remain->tv_sec = (__time32_t)remain64.tv_sec;
105        remain->tv_nsec = remain64.tv_nsec;
106    }
107
108    return 0;
109}