win_clock.c 4.6 KB

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