This commit is contained in:
Lucas Abad 2026-01-07 17:01:50 +08:00 committed by GitHub
commit b0ad4bf917
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 248 additions and 14 deletions

View File

@ -2135,7 +2135,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
// nanosleep(). This is incorrect, but good enough for now.
os_timespec ts;
convert_timestamp(in[0].u.u.clock.timeout, &ts);
nanosleep(&ts, NULL);
os_nanosleep(&ts, NULL);
}
break;
case __WASI_CLOCK_REALTIME:
@ -2163,7 +2163,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
// Relative sleeps can be done using nanosleep().
os_timespec ts;
convert_timestamp(in[0].u.u.clock.timeout, &ts);
nanosleep(&ts, NULL);
os_nanosleep(&ts, NULL);
}
break;
default:

View File

@ -6,6 +6,7 @@
#include <time.h>
#include "platform_api_extension.h"
#include "libc_errno.h"
int
os_usleep(uint32 usec)
@ -18,3 +19,13 @@ os_usleep(uint32 usec)
ret = nanosleep(&ts, NULL);
return ret == 0 ? 0 : -1;
}
__wasi_errno_t
os_nanosleep(const os_timespec *req, os_timespec *rem)
{
int ret;
ret = nanosleep(req, rem);
return convert_errno(ret);
}

View File

@ -1669,28 +1669,112 @@ __wasi_errno_t
os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
__wasi_timestamp_t *time);
#ifdef __cplusplus
}
#endif
/* Experimental */
/****************************************************
* Section 5 *
* Experimental functions *
****************************************************/
/* Used in posix.c around L2259 and expect the return code
* of ioctl() directly.
/**
* NOTES:
* The bellow functions were defined after increasing the support for the
* Zephyr platform to get the full WASI libc running.
*
* If you don't need to support WASI libc, there is no need to implement these
* APIs.
*
* We could also move these definitions to the proper sections
* (File, Time, ...) but still keep them here until we get more feedback or
* observe edges cases.
*/
/**
* @brief Control device.
*
* The `ioctl` function was one of the POSIX function used without platform
* abastraction API in the `sandboxed-system-primitives` and particularly in the
* `wasmtime_ssp_poll_oneoff` function.
*
* @param handle A platform file handler.
* @param request A platform-dependent request code.
* @param argp Usually an untyped pointer to memory.
*
* @return
* __WASI_ESUCCESS On success
* __WASI_EBADF handle is not a valid file handler.
* __WASI_EFAULT argp references an inaccessible memory area.
* __WASI_EINVAL request or argp is not valid.
* __WASI_ENOTTY handle is not associated with a character special device.
* __WASI_ENOTTY The specified request does not apply to the kind of
* object that the file handler handle references.
*
* NOTE: We seem to only use/support the `FIONREAD` request code:
*
* FIONREAD Get the number of bytes in the input buffer.
*/
int
os_ioctl(os_file_handle handle, int request, ...);
/* Higher level API:
* __wasi_errno_t
* blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
* os_nfds_t nfds, int timeout_ms, int *retp)
* Already format the errno and expect the return code of poll() directly.
/**
* @brief Wait for some event on a file descriptor.
*
* For more context, the higher level API `blocking_op_poll`.
*
* __wasi_errno_t
* blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
* os_nfds_t nfds, int timeout_ms, int *retp)
*
* Format the error code (errno) and expect the return code of (POSIX) `poll()`
* directly hence the `int` return type.
*
* @param pfds A poll file descriptors array
* @param nfs The size of the poll file descriptors array
* @param timeout Specify the number of ms that poll is busy waiting.
*
*/
int
os_poll(os_poll_file_handle *pfds, os_nfds_t nfs, int timeout);
/**
* @brief Compare two platform's file handle/descriptor.
*
* This function should ALWAYS be used when comparaing file handlers because
* for some platforms (Windows, Zephyr, etc...) the `os_file_handle` type is
* a structure and not a primary type like for POSIX.
*
* @param handle1 First file handle or constant.
* @param handle2 Second file handle.
*
* @return
* true The file handlers are similar.
* false The file handlers don't match.
*/
bool
os_compare_file_handle(os_file_handle handle1, os_file_handle handle2);
/**
* @brief high-resolution sleep
*
* The `nanosleep` function was the last POSIX function used without platform
* abastraction API in the `sandboxed-system-primitives` and particularly in the
* `wasmtime_ssp_poll_oneoff` function.
*
* @param req time requiered to sleep.
* @param rem remaining time in the case that the function is interrupted.
*
* @return
* __WASI_ESUCCESS On success
* __WASI_EFAULT Problem with copying information.
* __WASI_EINTR The sleep has been interrupted.
* __WASI_EINVAL The req input is badly formed.
*/
__wasi_errno_t
os_nanosleep(const os_timespec *req, os_timespec *rem);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef PLATFORM_API_EXTENSION_H */

View File

@ -67,6 +67,7 @@
#include <zephyr/net/net_core.h>
#include <zephyr/net/net_context.h>
#include <zephyr/net/socket.h>
#include <zephyr/fs/fs.h>
#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */
#ifdef CONFIG_USERSPACE
@ -300,7 +301,24 @@ typedef unsigned int os_nfds_t;
#define FIONREAD ZFD_IOCTL_FIONREAD
typedef struct timespec os_timespec;
/*
* The previous `os_timespec` was a forward declaration:
*
* typedef struct timespec os_timespec;
*
* It was not bad as is, but seemed to not be included from anywhere.
* As of Zephyr v3.7.0 (LTS) the `timespec` struct is only declared with the
* configuration `CONFIG_POSIX_API` enabled which is not a prefered
* configuration for the Zephyr port.
*
* NOTE: If Zephyr later exposes `struct timespec` without requiring
* CONFIG_POSIX_API, this definition should be replaced by an alias.
*/
typedef struct {
int64_t tv_sec;
long tv_nsec;
} os_timespec;
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 1

View File

@ -19,6 +19,7 @@ if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_socket.c)
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_file.c)
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_clock.c)
list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/zephyr_sleep.c)
else()
include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "platform_api_extension.h"
/*
* In Zephyr v3.7, there is no simple way to get a `nanosleep` implementation.
* But in the later version the Zephyr community introduced some clock APIs
* and their POSIX compatibility layer.
*
* Relevant Zephyr sources:
* - zephyr/include/zephyr/sys/clock.h
* - Zephyr/lib/os/clock.c
* POSIX layer:
* - zephyr/lib/posix/options/clock.c
*
* Instead of re-implementing the full Clock APIs, this file provides a naive
* `nanosleep` implementation based on the Zephyr thread API (`k_sleep`).
*
* Limitations:
* Maximum sleep duration is limited by UINT32_MAX or UINT64_MAX ticks
* ( 4,294,967,295 and 18,446,744,073,709,551,615 respectively).
*
* Example at a "slow" clock rate of 50 kHz:
* - UINT32_MAX: ~85 899s (~23 hours)
* - UINT64_MAX: ~368 934 881 474 191s (~11.7 millions years)
* Clearly, `nanosleep` should not be used for such long durations.
*
* Note: this assumes `CONFIG_POSIX_API=n` in the Zephyr application.
*/
static k_ticks_t timespec_to_ticks(const os_timespec *ts);
static void ticks_to_timespec(k_ticks_t ticks, os_timespec *ts);
__wasi_errno_t
os_nanosleep(const os_timespec *req, os_timespec *rem)
{
k_timeout_t timeout;
k_ticks_t rem_ticks;
if (req == NULL){
return __WASI_EINVAL;
}
if (req->tv_sec < 0 || req->tv_nsec < 0 || req->tv_nsec >= NSEC_PER_SEC) {
return __WASI_EINVAL;
}
if (req->tv_sec == 0 && req->tv_nsec == 0) {
if (rem != NULL) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
return __WASI_ESUCCESS;
}
timeout.ticks = timespec_to_ticks(req);
/*
* The function `int32_t k_sleep(k_timeout_t timeout)` return either:
* * 0 requested time elaspsed.
* * >0 remaining time in ms (due to k_wakeup).
*/
int32_t rc = k_sleep(timeout);
if (rem != NULL) {
if (rc > 0) {
#ifdef CONFIG_TIMEOUT_64BIT
rem_ticks = (k_ticks_t)((uint64_t)rc * CONFIG_SYS_CLOCK_TICKS_PER_SEC / MSEC_PER_SEC);
#else /* CONFIG_TIMEOUT_32BIT */
uint64_t temp_ticks = (uint64_t)rc * CONFIG_SYS_CLOCK_TICKS_PER_SEC / MSEC_PER_SEC;
rem_ticks = (k_ticks_t)(temp_ticks > UINT32_MAX ? UINT32_MAX : temp_ticks);
#endif
ticks_to_timespec(rem_ticks, rem);
} else {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
}
return __WASI_ESUCCESS;
}
static k_ticks_t timespec_to_ticks(const os_timespec *ts)
{
const uint64_t ticks_per_sec = CONFIG_SYS_CLOCK_TICKS_PER_SEC;
uint64_t total_ns, ticks;
total_ns = (uint64_t)ts->tv_sec * NSEC_PER_SEC + (uint64_t)ts->tv_nsec;
ticks = total_ns * ticks_per_sec / NSEC_PER_SEC;
#ifdef CONFIG_TIMEOUT_64BIT
if (ticks > INT64_MAX) {
return INT64_MAX;
}
#else /* CONFIG_TIMEOUT_32BIT */
if (ticks > UINT32_MAX) {
return UINT32_MAX;
}
#endif
return (k_ticks_t)ticks;
}
static void ticks_to_timespec(k_ticks_t ticks, os_timespec *ts)
{
const uint64_t ticks_per_sec = CONFIG_SYS_CLOCK_TICKS_PER_SEC;
uint64_t total_ns;
if (ts == NULL) {
return;
}
total_ns = ((uint64_t)ticks * NSEC_PER_SEC) / ticks_per_sec;
ts->tv_sec = (long)(total_ns / NSEC_PER_SEC);
ts->tv_nsec = (long)(total_ns % NSEC_PER_SEC);
}