win_clock.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * Copyright (C) 2023 Amazon Inc. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "platform_api_extension.h"
  6. #include <winternl.h>
  7. #include "win_util.h"
  8. #define NANOSECONDS_PER_SECOND 1000000000ULL
  9. #define NANOSECONDS_PER_TICK 100
  10. static __wasi_errno_t
  11. calculate_monotonic_clock_frequency(uint64 *out_frequency)
  12. {
  13. LARGE_INTEGER frequency;
  14. if (!QueryPerformanceFrequency(&frequency))
  15. return convert_windows_error_code(GetLastError());
  16. *out_frequency = (uint64)frequency.QuadPart;
  17. return __WASI_ESUCCESS;
  18. }
  19. static __wasi_errno_t
  20. get_performance_counter_value(uint64 *out_counter)
  21. {
  22. LARGE_INTEGER counter;
  23. if (!QueryPerformanceCounter(&counter))
  24. return convert_windows_error_code(GetLastError());
  25. *out_counter = counter.QuadPart;
  26. return __WASI_ESUCCESS;
  27. }
  28. __wasi_errno_t
  29. os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution)
  30. {
  31. __wasi_errno_t error = __WASI_ESUCCESS;
  32. switch (clock_id) {
  33. case __WASI_CLOCK_MONOTONIC:
  34. {
  35. uint64 frequency;
  36. error = calculate_monotonic_clock_frequency(&frequency);
  37. if (error != __WASI_ESUCCESS)
  38. return error;
  39. const uint64 result = (uint64)NANOSECONDS_PER_SECOND / frequency;
  40. *resolution = result;
  41. return error;
  42. }
  43. case __WASI_CLOCK_REALTIME:
  44. case __WASI_CLOCK_PROCESS_CPUTIME_ID:
  45. case __WASI_CLOCK_THREAD_CPUTIME_ID:
  46. {
  47. #if WINAPI_PARTITION_DESKTOP
  48. ULONG maximum_time;
  49. ULONG minimum_time;
  50. ULONG current_time;
  51. NTSTATUS
  52. status = NtQueryTimerResolution(&maximum_time, &minimum_time,
  53. &current_time);
  54. uint64 result = (uint64)current_time * NANOSECONDS_PER_TICK;
  55. *resolution = result / (uint64)NANOSECONDS_PER_SECOND;
  56. return error;
  57. #else
  58. return __WASI_ENOTSUP;
  59. #endif
  60. }
  61. default:
  62. return __WASI_EINVAL;
  63. }
  64. }
  65. __wasi_errno_t
  66. os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
  67. __wasi_timestamp_t *time)
  68. {
  69. __wasi_errno_t error = __WASI_ESUCCESS;
  70. switch (clock_id) {
  71. case __WASI_CLOCK_REALTIME:
  72. {
  73. FILETIME sys_now;
  74. #if NTDDI_VERSION >= NTDDI_WIN8
  75. GetSystemTimePreciseAsFileTime(&sys_now);
  76. #else
  77. GetSystemTimeAsFileTime(&sys_now);
  78. #endif
  79. *time = convert_filetime_to_wasi_timestamp(&sys_now);
  80. return BHT_OK;
  81. }
  82. case __WASI_CLOCK_MONOTONIC:
  83. {
  84. uint64 frequency;
  85. error = calculate_monotonic_clock_frequency(&frequency);
  86. if (error != __WASI_ESUCCESS)
  87. return error;
  88. uint64 counter;
  89. error = get_performance_counter_value(&counter);
  90. if (error != __WASI_ESUCCESS)
  91. return error;
  92. if (NANOSECONDS_PER_SECOND % frequency == 0) {
  93. *time = counter * NANOSECONDS_PER_SECOND / frequency;
  94. }
  95. else {
  96. uint64 seconds = counter / frequency;
  97. uint64 fractions = counter % frequency;
  98. *time = seconds * NANOSECONDS_PER_SECOND
  99. + (fractions * NANOSECONDS_PER_SECOND) / frequency;
  100. }
  101. return error;
  102. }
  103. case __WASI_CLOCK_PROCESS_CPUTIME_ID:
  104. case __WASI_CLOCK_THREAD_CPUTIME_ID:
  105. {
  106. FILETIME creation_time;
  107. FILETIME exit_time;
  108. FILETIME kernel_time;
  109. FILETIME user_time;
  110. HANDLE handle = (clock_id == __WASI_CLOCK_PROCESS_CPUTIME_ID)
  111. ? GetCurrentProcess()
  112. : GetCurrentThread();
  113. if (!GetProcessTimes(handle, &creation_time, &exit_time,
  114. &kernel_time, &user_time))
  115. return convert_windows_error_code(GetLastError());
  116. *time = convert_filetime_to_wasi_timestamp(&kernel_time)
  117. + convert_filetime_to_wasi_timestamp(&user_time);
  118. return error;
  119. }
  120. default:
  121. return __WASI_EINVAL;
  122. }
  123. }