// FIXME mingw-w64 commit https://sourceforge.net/p/mingw-w64/mingw-w64/ci/7b33798917a50cf023f1622eee8eba6d7874b796/ // A constructor is now run to determine which win32 api is used for the CLOCK_REALTIME clock. // But if a static variable calls clock_gettime in its constructor, it may call into a null function pointer. // This is what happens with the discord-rpc library so until this is fixed, we stick to the working version. /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifdef __GNUC__ #include #include #include #include #ifndef IN_WINPTHREAD #define IN_WINPTHREAD 1 #endif #include "pthread.h" #include "pthread_time.h" #define POW10_7 10000000 #define POW10_9 1000000000 /* Number of 100ns-seconds between the beginning of the Windows epoch * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970) */ #define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000) static WINPTHREADS_INLINE int lc_set_errno(int result) { if (result != 0) { errno = result; return -1; } return 0; } typedef void (WINAPI * GetSystemTimeAsFileTime_t)(LPFILETIME); static GetSystemTimeAsFileTime_t GetSystemTimeAsFileTime_p /* = 0 */; static GetSystemTimeAsFileTime_t try_load_GetSystemPreciseTimeAsFileTime(void) { /* Use GetSystemTimePreciseAsFileTime() if available (Windows 8 or later) */ HMODULE mod = GetModuleHandle("kernel32.dll"); GetSystemTimeAsFileTime_t get_time = NULL; if (mod) get_time = (GetSystemTimeAsFileTime_t)(intptr_t)GetProcAddress(mod, "GetSystemTimePreciseAsFileTime"); /* <1us precision on Windows 10 */ if (get_time == NULL) get_time = GetSystemTimeAsFileTime; /* >15ms precision on Windows 10 */ __atomic_store_n(&GetSystemTimeAsFileTime_p, get_time, __ATOMIC_RELAXED); return get_time; } static WINPTHREADS_INLINE GetSystemTimeAsFileTime_t load_GetSystemTimeBestAsFileTime(void) { GetSystemTimeAsFileTime_t get_time = __atomic_load_n(&GetSystemTimeAsFileTime_p, __ATOMIC_RELAXED); if (get_time == NULL) get_time = try_load_GetSystemPreciseTimeAsFileTime(); return get_time; } /** * Get the resolution of the specified clock clock_id and * stores it in the struct timespec pointed to by res. * @param clock_id The clock_id argument is the identifier of the particular * clock on which to act. The following clocks are supported: *
 *     CLOCK_REALTIME  System-wide real-time clock. Setting this clock
 *                 requires appropriate privileges.
 *     CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
 *                 time since some unspecified starting point.
 *     CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
 *     CLOCK_THREAD_CPUTIME_ID  Thread-specific CPU-time clock.
 * 
* @param res The pointer to a timespec structure to receive the time * resolution. * @return If the function succeeds, the return value is 0. * If the function fails, the return value is -1, * with errno set to indicate the error. */ int clock_getres(clockid_t clock_id, struct timespec *res) { clockid_t id = clock_id; if (id == CLOCK_REALTIME && load_GetSystemTimeBestAsFileTime() == GetSystemTimeAsFileTime) id = CLOCK_REALTIME_COARSE; /* GetSystemTimePreciseAsFileTime() not available */ switch(id) { case CLOCK_REALTIME: case CLOCK_MONOTONIC: { LARGE_INTEGER pf; if (QueryPerformanceFrequency(&pf) == 0) return lc_set_errno(EINVAL); res->tv_sec = 0; res->tv_nsec = (int) ((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart); if (res->tv_nsec < 1) res->tv_nsec = 1; return 0; } case CLOCK_REALTIME_COARSE: case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: { DWORD timeAdjustment, timeIncrement; BOOL isTimeAdjustmentDisabled; (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); res->tv_sec = 0; res->tv_nsec = timeIncrement * 100; return 0; } default: break; } return lc_set_errno(EINVAL); } /** * Get the time of the specified clock clock_id and stores it in the struct * timespec pointed to by tp. * @param clock_id The clock_id argument is the identifier of the particular * clock on which to act. The following clocks are supported: *
 *     CLOCK_REALTIME  System-wide real-time clock. Setting this clock
 *                 requires appropriate privileges.
 *     CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
 *                 time since some unspecified starting point.
 *     CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
 *     CLOCK_THREAD_CPUTIME_ID  Thread-specific CPU-time clock.
 * 
* @param tp The pointer to a timespec structure to receive the time. * @return If the function succeeds, the return value is 0. * If the function fails, the return value is -1, * with errno set to indicate the error. */ int clock_gettime(clockid_t clock_id, struct timespec *tp) { unsigned __int64 t; LARGE_INTEGER pf, pc; union { unsigned __int64 u64; FILETIME ft; } ct, et, kt, ut; switch(clock_id) { case CLOCK_REALTIME: { load_GetSystemTimeBestAsFileTime()(&ct.ft); t = ct.u64 - DELTA_EPOCH_IN_100NS; tp->tv_sec = t / POW10_7; tp->tv_nsec = ((int) (t % POW10_7)) * 100; return 0; } case CLOCK_REALTIME_COARSE: { GetSystemTimeAsFileTime(&ct.ft); t = ct.u64 - DELTA_EPOCH_IN_100NS; tp->tv_sec = t / POW10_7; tp->tv_nsec = ((int) (t % POW10_7)) * 100; return 0; } case CLOCK_MONOTONIC: { if (QueryPerformanceFrequency(&pf) == 0) return lc_set_errno(EINVAL); if (QueryPerformanceCounter(&pc) == 0) return lc_set_errno(EINVAL); tp->tv_sec = pc.QuadPart / pf.QuadPart; tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart); if (tp->tv_nsec >= POW10_9) { tp->tv_sec ++; tp->tv_nsec -= POW10_9; } return 0; } case CLOCK_PROCESS_CPUTIME_ID: { if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft)) return lc_set_errno(EINVAL); t = kt.u64 + ut.u64; tp->tv_sec = t / POW10_7; tp->tv_nsec = ((int) (t % POW10_7)) * 100; return 0; } case CLOCK_THREAD_CPUTIME_ID: { if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft)) return lc_set_errno(EINVAL); t = kt.u64 + ut.u64; tp->tv_sec = t / POW10_7; tp->tv_nsec = ((int) (t % POW10_7)) * 100; return 0; } default: break; } return lc_set_errno(EINVAL); } /** * Sleep for the specified time. * @param clock_id This argument should always be CLOCK_REALTIME (0). * @param flags 0 for relative sleep interval, others for absolute waking up. * @param request The desired sleep interval or absolute waking up time. * @param remain The remain amount of time to sleep. * The current implemention just ignore it. * @return If the function succeeds, the return value is 0. * If the function fails, the return value is -1, * with errno set to indicate the error. */ int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain) { struct timespec tp; if (clock_id != CLOCK_REALTIME) return lc_set_errno(EINVAL); if (flags == 0) return nanosleep(request, remain); /* TIMER_ABSTIME = 1 */ clock_gettime(CLOCK_REALTIME, &tp); tp.tv_sec = request->tv_sec - tp.tv_sec; tp.tv_nsec = request->tv_nsec - tp.tv_nsec; if (tp.tv_nsec < 0) { tp.tv_nsec += POW10_9; tp.tv_sec --; } return nanosleep(&tp, remain); } /** * Set the time of the specified clock clock_id. * @param clock_id This argument should always be CLOCK_REALTIME (0). * @param tp The requested time. * @return If the function succeeds, the return value is 0. * If the function fails, the return value is -1, * with errno set to indicate the error. */ int clock_settime(clockid_t clock_id, const struct timespec *tp) { SYSTEMTIME st; union { unsigned __int64 u64; FILETIME ft; } t; if (clock_id != CLOCK_REALTIME) return lc_set_errno(EINVAL); t.u64 = tp->tv_sec * (__int64) POW10_7 + tp->tv_nsec / 100 + DELTA_EPOCH_IN_100NS; if (FileTimeToSystemTime(&t.ft, &st) == 0) return lc_set_errno(EINVAL); if (SetSystemTime(&st) == 0) return lc_set_errno(EPERM); return 0; } #endif