win_clock.c 4.4 KB

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