| 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 | */ |
| 40 | static 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 | |
| 85 | int nanosleep64(const struct _timespec64 *request, struct _timespec64 *remain) |
| 86 | { |
| 87 | return __nanosleep (request, remain); |
| 88 | } |
| 89 | |
| 90 | int 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 | } |