1*9a06fb7eSSchrodinger ZHU Yifan //===-- Windows implementation of clock_getres ------------------*- C++ -*-===// 2*9a06fb7eSSchrodinger ZHU Yifan // 3*9a06fb7eSSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*9a06fb7eSSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 5*9a06fb7eSSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*9a06fb7eSSchrodinger ZHU Yifan // 7*9a06fb7eSSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 8*9a06fb7eSSchrodinger ZHU Yifan 9*9a06fb7eSSchrodinger ZHU Yifan #include "hdr/errno_macros.h" 10*9a06fb7eSSchrodinger ZHU Yifan #include "hdr/time_macros.h" 11*9a06fb7eSSchrodinger ZHU Yifan #include "hdr/types/clockid_t.h" 12*9a06fb7eSSchrodinger ZHU Yifan #include "hdr/types/struct_timespec.h" 13*9a06fb7eSSchrodinger ZHU Yifan 14*9a06fb7eSSchrodinger ZHU Yifan #include "src/__support/CPP/limits.h" 15*9a06fb7eSSchrodinger ZHU Yifan #include "src/__support/common.h" 16*9a06fb7eSSchrodinger ZHU Yifan #include "src/__support/macros/optimization.h" 17*9a06fb7eSSchrodinger ZHU Yifan #include "src/__support/time/units.h" 18*9a06fb7eSSchrodinger ZHU Yifan #include "src/__support/time/windows/performance_counter.h" 19*9a06fb7eSSchrodinger ZHU Yifan #include "src/errno/libc_errno.h" 20*9a06fb7eSSchrodinger ZHU Yifan #include "src/time/clock_getres.h" 21*9a06fb7eSSchrodinger ZHU Yifan 22*9a06fb7eSSchrodinger ZHU Yifan #define WIN32_LEAN_AND_MEAN 23*9a06fb7eSSchrodinger ZHU Yifan #define NOMINMAX 24*9a06fb7eSSchrodinger ZHU Yifan #include <Windows.h> 25*9a06fb7eSSchrodinger ZHU Yifan 26*9a06fb7eSSchrodinger ZHU Yifan // add in dependencies for GetSystemTimeAdjustmentPrecise 27*9a06fb7eSSchrodinger ZHU Yifan #pragma comment(lib, "mincore.lib") 28*9a06fb7eSSchrodinger ZHU Yifan 29*9a06fb7eSSchrodinger ZHU Yifan namespace LIBC_NAMESPACE_DECL { 30*9a06fb7eSSchrodinger ZHU Yifan LLVM_LIBC_FUNCTION(int, clock_getres, (clockid_t id, struct timespec *res)) { 31*9a06fb7eSSchrodinger ZHU Yifan using namespace time_units; 32*9a06fb7eSSchrodinger ZHU Yifan // POSIX allows nullptr to be passed as res, in which case the function should 33*9a06fb7eSSchrodinger ZHU Yifan // do nothing. 34*9a06fb7eSSchrodinger ZHU Yifan if (res == nullptr) 35*9a06fb7eSSchrodinger ZHU Yifan return 0; 36*9a06fb7eSSchrodinger ZHU Yifan constexpr unsigned long long HNS_PER_SEC = 1_s_ns / 100ULL; 37*9a06fb7eSSchrodinger ZHU Yifan constexpr unsigned long long SEC_LIMIT = 38*9a06fb7eSSchrodinger ZHU Yifan cpp::numeric_limits<decltype(res->tv_sec)>::max(); 39*9a06fb7eSSchrodinger ZHU Yifan // For CLOCK_MONOTONIC, we are using performance counter 40*9a06fb7eSSchrodinger ZHU Yifan // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps 41*9a06fb7eSSchrodinger ZHU Yifan // Hence, the resolution is given by the performance counter frequency. 42*9a06fb7eSSchrodinger ZHU Yifan // For CLOCK_REALTIME, the precision is given by 43*9a06fb7eSSchrodinger ZHU Yifan // GetSystemTimeAdjustmentPrecise 44*9a06fb7eSSchrodinger ZHU Yifan // (https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeadjustmentprecise) 45*9a06fb7eSSchrodinger ZHU Yifan // For CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, the precision is 46*9a06fb7eSSchrodinger ZHU Yifan // given by GetSystemTimeAdjustment 47*9a06fb7eSSchrodinger ZHU Yifan // (https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeadjustment) 48*9a06fb7eSSchrodinger ZHU Yifan switch (id) { 49*9a06fb7eSSchrodinger ZHU Yifan default: 50*9a06fb7eSSchrodinger ZHU Yifan libc_errno = EINVAL; 51*9a06fb7eSSchrodinger ZHU Yifan return -1; 52*9a06fb7eSSchrodinger ZHU Yifan 53*9a06fb7eSSchrodinger ZHU Yifan case CLOCK_MONOTONIC: { 54*9a06fb7eSSchrodinger ZHU Yifan long long freq = performance_counter::get_ticks_per_second(); 55*9a06fb7eSSchrodinger ZHU Yifan __builtin_assume(freq != 0); 56*9a06fb7eSSchrodinger ZHU Yifan // division of 1 second by frequency, rounded up. 57*9a06fb7eSSchrodinger ZHU Yifan long long tv_sec = static_cast<long long>(freq == 1); 58*9a06fb7eSSchrodinger ZHU Yifan long long tv_nsec = 59*9a06fb7eSSchrodinger ZHU Yifan LIBC_LIKELY(freq != 1) ? 1ll + ((1_s_ns - 1ll) / freq) : 0ll; 60*9a06fb7eSSchrodinger ZHU Yifan // not possible to overflow tv_sec, tv_nsec 61*9a06fb7eSSchrodinger ZHU Yifan res->tv_sec = static_cast<decltype(res->tv_sec)>(tv_sec); 62*9a06fb7eSSchrodinger ZHU Yifan res->tv_nsec = static_cast<decltype(res->tv_nsec)>(tv_nsec); 63*9a06fb7eSSchrodinger ZHU Yifan break; 64*9a06fb7eSSchrodinger ZHU Yifan } 65*9a06fb7eSSchrodinger ZHU Yifan 66*9a06fb7eSSchrodinger ZHU Yifan case CLOCK_REALTIME: { 67*9a06fb7eSSchrodinger ZHU Yifan [[clang::uninitialized]] DWORD64 time_adjustment; 68*9a06fb7eSSchrodinger ZHU Yifan [[clang::uninitialized]] DWORD64 time_increment; 69*9a06fb7eSSchrodinger ZHU Yifan [[clang::uninitialized]] BOOL time_adjustment_disabled; 70*9a06fb7eSSchrodinger ZHU Yifan if (!::GetSystemTimeAdjustmentPrecise(&time_adjustment, &time_increment, 71*9a06fb7eSSchrodinger ZHU Yifan &time_adjustment_disabled)) { 72*9a06fb7eSSchrodinger ZHU Yifan libc_errno = EINVAL; 73*9a06fb7eSSchrodinger ZHU Yifan return -1; 74*9a06fb7eSSchrodinger ZHU Yifan } 75*9a06fb7eSSchrodinger ZHU Yifan DWORD64 tv_sec = time_increment / HNS_PER_SEC; 76*9a06fb7eSSchrodinger ZHU Yifan DWORD64 tv_nsec = (time_increment % HNS_PER_SEC) * 100ULL; 77*9a06fb7eSSchrodinger ZHU Yifan if (LIBC_UNLIKELY(tv_sec > SEC_LIMIT)) { 78*9a06fb7eSSchrodinger ZHU Yifan libc_errno = EOVERFLOW; 79*9a06fb7eSSchrodinger ZHU Yifan return -1; 80*9a06fb7eSSchrodinger ZHU Yifan } 81*9a06fb7eSSchrodinger ZHU Yifan res->tv_sec = static_cast<decltype(res->tv_sec)>(tv_sec); 82*9a06fb7eSSchrodinger ZHU Yifan res->tv_nsec = static_cast<decltype(res->tv_nsec)>(tv_nsec); 83*9a06fb7eSSchrodinger ZHU Yifan break; 84*9a06fb7eSSchrodinger ZHU Yifan } 85*9a06fb7eSSchrodinger ZHU Yifan case CLOCK_PROCESS_CPUTIME_ID: 86*9a06fb7eSSchrodinger ZHU Yifan case CLOCK_THREAD_CPUTIME_ID: { 87*9a06fb7eSSchrodinger ZHU Yifan [[clang::uninitialized]] DWORD time_adjustment; 88*9a06fb7eSSchrodinger ZHU Yifan [[clang::uninitialized]] DWORD time_increment; 89*9a06fb7eSSchrodinger ZHU Yifan [[clang::uninitialized]] BOOL time_adjustment_disabled; 90*9a06fb7eSSchrodinger ZHU Yifan if (!::GetSystemTimeAdjustment(&time_adjustment, &time_increment, 91*9a06fb7eSSchrodinger ZHU Yifan &time_adjustment_disabled)) { 92*9a06fb7eSSchrodinger ZHU Yifan libc_errno = EINVAL; 93*9a06fb7eSSchrodinger ZHU Yifan return -1; 94*9a06fb7eSSchrodinger ZHU Yifan } 95*9a06fb7eSSchrodinger ZHU Yifan DWORD hns_per_sec = static_cast<DWORD>(HNS_PER_SEC); 96*9a06fb7eSSchrodinger ZHU Yifan DWORD sec_limit = static_cast<DWORD>(SEC_LIMIT); 97*9a06fb7eSSchrodinger ZHU Yifan DWORD tv_sec = time_increment / hns_per_sec; 98*9a06fb7eSSchrodinger ZHU Yifan DWORD tv_nsec = (time_increment % hns_per_sec) * 100UL; 99*9a06fb7eSSchrodinger ZHU Yifan if (LIBC_UNLIKELY(tv_sec > sec_limit)) { 100*9a06fb7eSSchrodinger ZHU Yifan libc_errno = EOVERFLOW; 101*9a06fb7eSSchrodinger ZHU Yifan return -1; 102*9a06fb7eSSchrodinger ZHU Yifan } 103*9a06fb7eSSchrodinger ZHU Yifan res->tv_sec = static_cast<decltype(res->tv_sec)>(tv_sec); 104*9a06fb7eSSchrodinger ZHU Yifan res->tv_nsec = static_cast<decltype(res->tv_nsec)>(tv_nsec); 105*9a06fb7eSSchrodinger ZHU Yifan break; 106*9a06fb7eSSchrodinger ZHU Yifan } 107*9a06fb7eSSchrodinger ZHU Yifan } 108*9a06fb7eSSchrodinger ZHU Yifan return 0; 109*9a06fb7eSSchrodinger ZHU Yifan } 110*9a06fb7eSSchrodinger ZHU Yifan } // namespace LIBC_NAMESPACE_DECL 111