diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index d143f7bef..f6479a20d 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -94,22 +94,9 @@ ns_lookup_list_search(char **list, const char *host) return false; } -// Converts a POSIX timespec to a CloudABI timestamp. -static __wasi_timestamp_t -convert_timespec(const struct timespec *ts) -{ - if (ts->tv_sec < 0) - return 0; - if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000) - return UINT64_MAX; - return (__wasi_timestamp_t)ts->tv_sec * 1000000000 - + (__wasi_timestamp_t)ts->tv_nsec; -} - -// Converts a CloudABI clock identifier to a POSIX clock identifier. #ifndef BH_PLATFORM_WINDOWS static bool -convert_clockid(__wasi_clockid_t in, clockid_t *out) +wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out) { switch (in) { case __WASI_CLOCK_MONOTONIC: @@ -210,22 +197,37 @@ wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr, } } +static bool +wasi_clockid_to_bh_clockid(__wasi_clockid_t in, bh_clock_id_t *out) +{ + switch (in) { + case __WASI_CLOCK_MONOTONIC: + *out = BH_CLOCK_ID_MONOTONIC; + return true; + case __WASI_CLOCK_PROCESS_CPUTIME_ID: + *out = BH_CLOCK_ID_PROCESS_CPUTIME_ID; + return true; + case __WASI_CLOCK_REALTIME: + *out = BH_CLOCK_ID_REALTIME; + return true; + case __WASI_CLOCK_THREAD_CPUTIME_ID: + *out = BH_CLOCK_ID_THREAD_CPUTIME_ID; + return true; + default: + return false; + } +} + __wasi_errno_t wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) { -#ifdef BH_PLATFORM_WINDOWS - return __WASI_ENOSYS; -#else - clockid_t nclock_id; - if (!convert_clockid(clock_id, &nclock_id)) + bh_clock_id_t bh_clockid; + if (!wasi_clockid_to_bh_clockid(clock_id, &bh_clockid)) return __WASI_EINVAL; - struct timespec ts; - if (clock_getres(nclock_id, &ts) < 0) + if (os_clock_res_get(clock_id, resolution) != BHT_OK) return convert_errno(errno); - *resolution = convert_timespec(&ts); - return 0; -#endif + return __WASI_ESUCCESS; } __wasi_errno_t @@ -233,18 +235,12 @@ wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, __wasi_timestamp_t *time) { -#ifdef BH_PLATFORM_WINDOWS - return __WASI_ENOSYS; -#else - clockid_t nclock_id; - if (!convert_clockid(clock_id, &nclock_id)) + bh_clock_id_t bh_clockid; + if (!wasi_clockid_to_bh_clockid(clock_id, &bh_clockid)) return __WASI_EINVAL; - struct timespec ts; - if (clock_gettime(nclock_id, &ts) < 0) + if (os_clock_time_get(clock_id, precision, time) != BHT_OK) return convert_errno(errno); - *time = convert_timespec(&ts); - return 0; -#endif + return __WASI_ESUCCESS; } struct fd_prestat { @@ -2081,7 +2077,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, }; #if CONFIG_HAS_CLOCK_NANOSLEEP clockid_t clock_id; - if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) { + if (wasi_clockid_to_clockid(in[0].u.u.clock.clock_id, &clock_id)) { struct timespec ts; convert_timestamp(in[0].u.u.clock.timeout, &ts); int ret = clock_nanosleep( diff --git a/core/shared/platform/common/posix/posix_clock.c b/core/shared/platform/common/posix/posix_clock.c new file mode 100644 index 000000000..3c9f9d56b --- /dev/null +++ b/core/shared/platform/common/posix/posix_clock.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +#define NANOSECONDS_PER_SECOND 1000000000ULL + +static bool +bh_clockid_to_clockid(bh_clock_id_t in, clockid_t *out) +{ + switch (in) { + case BH_CLOCK_ID_MONOTONIC: + *out = CLOCK_MONOTONIC; + return true; +#if defined(CLOCK_PROCESS_CPUTIME_ID) + case BH_CLOCK_ID_PROCESS_CPUTIME_ID: + *out = CLOCK_PROCESS_CPUTIME_ID; + return true; +#endif + case BH_CLOCK_ID_REALTIME: + *out = CLOCK_REALTIME; + return true; +#if defined(CLOCK_THREAD_CPUTIME_ID) + case BH_CLOCK_ID_THREAD_CPUTIME_ID: + *out = CLOCK_THREAD_CPUTIME_ID; + return true; +#endif + default: + errno = EINVAL; + return false; + } +} + +static uint64 +timespec_to_nanoseconds(const struct timespec *ts) +{ + if (ts->tv_sec < 0) + return 0; + if ((uint64)ts->tv_sec >= UINT64_MAX / NANOSECONDS_PER_SECOND) + return UINT64_MAX; + return (uint64)ts->tv_sec * NANOSECONDS_PER_SECOND + (uint64)ts->tv_nsec; +} + +int +os_clock_res_get(bh_clock_id_t clock_id, uint64 *resolution) +{ + clockid_t nclock_id; + if (!bh_clockid_to_clockid(clock_id, &nclock_id)) + return BHT_ERROR; + struct timespec ts; + if (clock_getres(nclock_id, &ts) < 0) + return BHT_ERROR; + *resolution = timespec_to_nanoseconds(&ts); + + return BHT_OK; +} + +int +os_clock_time_get(bh_clock_id_t clock_id, uint64 precision, uint64 *time) +{ + clockid_t nclock_id; + if (!bh_clockid_to_clockid(clock_id, &nclock_id)) + return BHT_ERROR; + struct timespec ts; + if (clock_gettime(nclock_id, &ts) < 0) + return BHT_ERROR; + *time = timespec_to_nanoseconds(&ts); + + return 0; +} diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index e40ddfd05..381d66fd6 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -36,6 +36,26 @@ extern "C" { * 2. To build the app-mgr and app-framework, you must implement it */ +/** + * Get a resolution of the clock + * + * @param clock_id clock identifier + * @param resolution output variable to store the clock resolution + * @return BHT_OK if success; otherwise, BHT_ERROR + */ +int +os_clock_res_get(bh_clock_id_t clock_id, uint64 *resolution); + +/** + * Get a current time of the clock + * + * @param clock_id clock identifier + * @param time output variable to store the clock time + * @return BHT_OK if success; otherwise, BHT_ERROR + */ +int +os_clock_time_get(bh_clock_id_t clock_id, uint64 precision, uint64 *time); + /** * Creates a thread * diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 28001af74..62d3e83ed 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -37,6 +37,13 @@ extern "C" { #define BH_TIME_T_MAX LONG_MAX #endif +typedef enum { + BH_CLOCK_ID_REALTIME, + BH_CLOCK_ID_MONOTONIC, + BH_CLOCK_ID_PROCESS_CPUTIME_ID, + BH_CLOCK_ID_THREAD_CPUTIME_ID +} bh_clock_id_t; + #if defined(_MSC_BUILD) #if defined(COMPILING_WASM_RUNTIME_API) __declspec(dllexport) void *BH_MALLOC(unsigned int size); diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index 1168dedbc..4fe5d9020 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/core/shared/platform/linux-sgx/shared_platform.cmake @@ -36,6 +36,8 @@ endif() file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c) +list(APPEND source_all ${PLATFORM_SHARED_DIR}/../common/posix/posix_clock.c) + set (PLATFORM_SHARED_SOURCE ${source_all}) set (PLATFORM_SHARED_SOURCE_UNTRUSTED ${source_all_untrusted}) diff --git a/core/shared/platform/windows/win_clock.c b/core/shared/platform/windows/win_clock.c new file mode 100644 index 000000000..4e1a5e89c --- /dev/null +++ b/core/shared/platform/windows/win_clock.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include + +#define NANOSECONDS_PER_SECOND 1000000000ULL +#define NANOSECONDS_PER_TICK 100 + +static int +calculate_monotonic_clock_frequency(uint64 *out_frequency) +{ + LARGE_INTEGER frequency; + if (!QueryPerformanceFrequency(&frequency)) { + return BHT_ERROR; + } + else { + *out_frequency = (uint64)frequency.QuadPart; + return BHT_OK; + } +} + +// The implementation below derives from the following source: +// https://github.com/WasmEdge/WasmEdge/blob/b70f48c42922ce5ee7730054b6ac0b1615176285/lib/host/wasi/win.h#L210 +static uint64 +filetime_to_wasi_timestamp(FILETIME filetime) +{ + static const uint64 ntto_unix_epoch = + 134774ULL * 86400ULL * NANOSECONDS_PER_SECOND; + + ULARGE_INTEGER temp = { .LowPart = filetime.dwLowDateTime, + .HighPart = filetime.dwHighDateTime }; + + return (temp.QuadPart * 100ull) - ntto_unix_epoch; +} + +static int +get_performance_counter_value(uint64 *out_counter) +{ + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return BHT_ERROR; + } + else { + *out_counter = counter.QuadPart; + return BHT_OK; + } +} + +int +os_clock_res_get(bh_clock_id_t clock_id, uint64 *resolution) +{ + switch (clock_id) { + case BH_CLOCK_ID_MONOTONIC: + { + uint64 frequency; + if (calculate_monotonic_clock_frequency(&frequency) == BHT_ERROR) { + return BHT_ERROR; + } + const uint64 result = (uint64)NANOSECONDS_PER_SECOND / frequency; + *resolution = result; + return BHT_OK; + } + case BH_CLOCK_ID_REALTIME: + case BH_CLOCK_ID_PROCESS_CPUTIME_ID: + case BH_CLOCK_ID_THREAD_CPUTIME_ID: + { + PULONG maximum_time; + PULONG minimum_time; + PULONG current_time; + NTSTATUS + status = NtQueryTimerResolution(&maximum_time, &minimum_time, + ¤t_time); + + uint64 result = (uint64)current_time * NANOSECONDS_PER_TICK; + *resolution = result / (uint64)NANOSECONDS_PER_SECOND; + return BHT_OK; + } + default: + errno = EINVAL; + return BHT_ERROR; + } +} + +int +os_clock_time_get(bh_clock_id_t clock_id, uint64 precision, uint64 *time) +{ + switch (clock_id) { + case BH_CLOCK_ID_REALTIME: + { + FILETIME sys_now; +#if NTDDI_VERSION >= NTDDI_WIN8 + GetSystemTimePreciseAsFileTime(&sys_now); +#else + GetSystemTimeAsFileTime(&SysNow); +#endif + *time = filetime_to_wasi_timestamp(sys_now); + return BHT_OK; + } + case BH_CLOCK_ID_MONOTONIC: + { + uint64 frequency; + if (calculate_monotonic_clock_frequency(&frequency) == BHT_ERROR) { + return BHT_ERROR; + } + uint64 counter; + if (get_performance_counter_value(&counter) == BHT_ERROR) { + return BHT_ERROR; + } + if (NANOSECONDS_PER_SECOND % frequency == 0) { + *time = counter * NANOSECONDS_PER_SECOND / frequency; + } + else { + uint64 seconds = counter / frequency; + uint64 fractions = counter % frequency; + *time = seconds * NANOSECONDS_PER_SECOND + + (fractions * NANOSECONDS_PER_SECOND) / frequency; + } + return BHT_OK; + } + case BH_CLOCK_ID_PROCESS_CPUTIME_ID: + { + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + + if (!GetProcessTimes(GetCurrentProcess(), &creation_time, + &exit_time, &kernel_time, &user_time)) { + return BHT_ERROR; + } + *time = filetime_to_wasi_timestamp(kernel_time) + + filetime_to_wasi_timestamp(user_time); + + return BHT_OK; + } + case BH_CLOCK_ID_THREAD_CPUTIME_ID: + { + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + + if (!GetProcessTimes(GetCurrentThread(), &creation_time, &exit_time, + &kernel_time, &user_time)) { + return BHT_ERROR; + } + + *time = filetime_to_wasi_timestamp(kernel_time) + + filetime_to_wasi_timestamp(user_time); + + return BHT_OK; + } + default: + errno = EINVAL; + return BHT_ERROR; + } +} \ No newline at end of file diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 099c5503c..ec7508e94 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -364,6 +364,7 @@ CSRCS += nuttx_platform.c \ posix_blocking_op.c \ posix_thread.c \ posix_time.c \ + posix_clock.c \ posix_sleep.c \ mem_alloc.c \ ems_kfc.c \ diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 07fe46a68..02aa3f31b 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -153,3 +153,9 @@ target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS}) if (MINGW) target_link_libraries (libiwasm ws2_32) endif () + +if (WIN32) + target_link_libraries(libiwasm ntdll) + + target_link_libraries(iwasm ntdll) +endif()