Skip to content

Commit

Permalink
zephyr: Enable WASI support for file system and sockets on zephyr (#3633
Browse files Browse the repository at this point in the history
)

To address #3311.

This work also implements the WASI support on Zephyr.

Note that some comments haven't been addressed and will be fixed in the
further patches.
  • Loading branch information
lucasAbadFr authored Nov 6, 2024
1 parent e352f0a commit 0464262
Show file tree
Hide file tree
Showing 48 changed files with 9,673 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,14 @@ blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
#ifndef BH_PLATFORM_WINDOWS
/* REVISIT: apply the os_file_handle style abstraction for pollfd? */
__wasi_errno_t
blocking_op_poll(wasm_exec_env_t exec_env, struct pollfd *pfds, nfds_t nfds,
int timeout_ms, int *retp)
blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
os_nfds_t nfds, int timeout_ms, int *retp)
{
int ret;
if (!wasm_runtime_begin_blocking_op(exec_env)) {
return __WASI_EINTR;
}
ret = poll(pfds, nfds, timeout_ms);
ret = os_poll(pfds, nfds, timeout_ms);
wasm_runtime_end_blocking_op(exec_env);
if (ret == -1) {
return convert_errno(errno);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,

#ifndef BH_PLATFORM_WINDOWS
__wasi_errno_t
blocking_op_poll(wasm_exec_env_t exec_env, struct pollfd *pfds, nfds_t nfds,
int timeout, int *retp);
blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds,
os_nfds_t nfds, int timeout, int *retp);
#endif

#endif /* end of _BLOCKING_OP_H_ */
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,12 @@ static inline bool
cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
bool abstime) REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
{
#if defined(BH_PLATFORM_ZEPHYR)
// TODO: Implement this for Zephyr
return false;
#else
int ret;
struct timespec ts = {
os_timespec ts = {
.tv_sec = (time_t)(timeout / 1000000000),
.tv_nsec = (long)(timeout % 1000000000),
};
Expand All @@ -210,8 +214,8 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
* realtime clock.
*/
if (cond->clock != CLOCK_REALTIME) {
struct timespec ts_monotonic;
struct timespec ts_realtime;
os_timespec ts_monotonic;
os_timespec ts_realtime;

clock_gettime(cond->clock, &ts_monotonic);
ts.tv_sec -= ts_monotonic.tv_sec;
Expand All @@ -229,7 +233,7 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
++ts.tv_sec;
}
}
#endif
#endif /* !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK */
}
else {
#if CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
Expand All @@ -241,7 +245,7 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
return ret == ETIMEDOUT;
#else
/* Convert to absolute timeout. */
struct timespec ts_now;
os_timespec ts_now;
#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
clock_gettime(cond->clock, &ts_now);
#else
Expand All @@ -253,13 +257,14 @@ cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
#endif
#endif /* CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP */
}

ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts);
bh_assert((ret == 0 || ret == ETIMEDOUT)
&& "pthread_cond_timedwait() failed");
return ret == ETIMEDOUT;
#endif /* BH_PLATFORM_ZEPHYR */
}
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,16 +356,20 @@ fd_table_get_entry(struct fd_table *ft, __wasi_fd_t fd,
REQUIRES_SHARED(ft->lock)
{
// Test for file descriptor existence.
if (fd >= ft->size)
if (fd >= ft->size) {
return __WASI_EBADF;
}

struct fd_entry *fe = &ft->entries[fd];
if (fe->object == NULL)
if (fe->object == NULL) {
return __WASI_EBADF;
}

// Validate rights.
if ((~fe->rights_base & rights_base) != 0
|| (~fe->rights_inheriting & rights_inheriting) != 0)
|| (~fe->rights_inheriting & rights_inheriting) != 0) {
return __WASI_ENOTCAPABLE;
}
*ret = fe;
return 0;
}
Expand Down Expand Up @@ -426,28 +430,28 @@ fd_table_attach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object *fo,
__wasi_rights_t rights_base, __wasi_rights_t rights_inheriting)
REQUIRES_EXCLUSIVE(ft->lock) CONSUMES(fo->refcount)
{
assert(ft->size > fd && "File descriptor table too small");
bh_assert(ft->size > fd && "File descriptor table too small");
struct fd_entry *fe = &ft->entries[fd];
assert(fe->object == NULL
&& "Attempted to overwrite an existing descriptor");
bh_assert(fe->object == NULL
&& "Attempted to overwrite an existing descriptor");
fe->object = fo;
fe->rights_base = rights_base;
fe->rights_inheriting = rights_inheriting;
++ft->used;
assert(ft->size >= ft->used * 2 && "File descriptor too full");
bh_assert(ft->size >= ft->used * 2 && "File descriptor too full");
}

// Detaches a file descriptor from the file descriptor table.
static void
fd_table_detach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object **fo)
REQUIRES_EXCLUSIVE(ft->lock) PRODUCES((*fo)->refcount)
{
assert(ft->size > fd && "File descriptor table too small");
bh_assert(ft->size > fd && "File descriptor table too small");
struct fd_entry *fe = &ft->entries[fd];
*fo = fe->object;
assert(*fo != NULL && "Attempted to detach nonexistent descriptor");
bh_assert(*fo != NULL && "Attempted to detach nonexistent descriptor");
fe->object = NULL;
assert(ft->used > 0 && "Reference count mismatch");
bh_assert(ft->used > 0 && "Reference count mismatch");
--ft->used;
}

Expand Down Expand Up @@ -636,7 +640,7 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in,
static __wasi_errno_t
fd_table_unused(struct fd_table *ft, __wasi_fd_t *out) REQUIRES_SHARED(ft->lock)
{
assert(ft->size > ft->used && "File descriptor table has no free slots");
bh_assert(ft->size > ft->used && "File descriptor table has no free slots");
for (;;) {
uintmax_t random_fd = 0;
__wasi_errno_t error = random_uniform(ft->size, &random_fd);
Expand Down Expand Up @@ -1537,7 +1541,8 @@ path_put(struct path_access *pa) UNLOCKS(pa->fd_object->refcount)
{
if (pa->path_start)
wasm_runtime_free(pa->path_start);
if (pa->fd_object->file_handle != pa->fd)
/* Can't use `!=` operator when `os_file_handle` is a struct */
if (!os_compare_file_handle(pa->fd_object->file_handle, pa->fd))
os_close(pa->fd, false);
fd_object_release(NULL, pa->fd_object);
}
Expand Down Expand Up @@ -1878,7 +1883,7 @@ wasmtime_ssp_fd_filestat_get(wasm_exec_env_t exec_env, struct fd_table *curfds,
}

static void
convert_timestamp(__wasi_timestamp_t in, struct timespec *out)
convert_timestamp(__wasi_timestamp_t in, os_timespec *out)
{
// Store sub-second remainder.
#if defined(__SYSCALL_SLONG_TYPE)
Expand Down Expand Up @@ -2076,7 +2081,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
size_t nsubscriptions,
size_t *nevents) NO_LOCK_ANALYSIS
{
#ifdef BH_PLATFORM_WINDOWS
#if defined(BH_PLATFORM_WINDOWS) || defined(BH_PLATFORM_ZEPHYR)
return __WASI_ENOSYS;
#else
// Sleeping.
Expand All @@ -2088,7 +2093,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 (wasi_clockid_to_clockid(in[0].u.u.clock.clock_id, &clock_id)) {
struct timespec ts;
os_timespec ts;
convert_timestamp(in[0].u.u.clock.timeout, &ts);
int ret = clock_nanosleep(
clock_id,
Expand All @@ -2115,7 +2120,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
else {
// Perform relative sleeps on the monotonic clock also using
// nanosleep(). This is incorrect, but good enough for now.
struct timespec ts;
os_timespec ts;
convert_timestamp(in[0].u.u.clock.timeout, &ts);
nanosleep(&ts, NULL);
}
Expand Down Expand Up @@ -2143,7 +2148,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
}
else {
// Relative sleeps can be done using nanosleep().
struct timespec ts;
os_timespec ts;
convert_timestamp(in[0].u.u.clock.timeout, &ts);
nanosleep(&ts, NULL);
}
Expand All @@ -2168,7 +2173,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
wasm_runtime_malloc((uint32)(nsubscriptions * sizeof(*fos)));
if (fos == NULL)
return __WASI_ENOMEM;
struct pollfd *pfds =
os_poll_file_handle *pfds =
wasm_runtime_malloc((uint32)(nsubscriptions * sizeof(*pfds)));
if (pfds == NULL) {
wasm_runtime_free(fos);
Expand All @@ -2193,7 +2198,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
__WASI_RIGHT_POLL_FD_READWRITE, 0);
if (error == 0) {
// Proper file descriptor on which we can poll().
pfds[i] = (struct pollfd){
pfds[i] = (os_poll_file_handle){
.fd = fos[i]->file_handle,
.events = s->u.type == __WASI_EVENTTYPE_FD_READ
? POLLIN
Expand All @@ -2203,7 +2208,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
else {
// Invalid file descriptor or rights missing.
fos[i] = NULL;
pfds[i] = (struct pollfd){ .fd = -1 };
pfds[i] = (os_poll_file_handle){ .fd = -1 };
out[(*nevents)++] = (__wasi_event_t){
.userdata = s->userdata,
.error = error,
Expand All @@ -2218,15 +2223,15 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
== 0) {
// Relative timeout.
fos[i] = NULL;
pfds[i] = (struct pollfd){ .fd = -1 };
pfds[i] = (os_poll_file_handle){ .fd = -1 };
clock_subscription = s;
break;
}
// Fallthrough.
default:
// Unsupported event.
fos[i] = NULL;
pfds[i] = (struct pollfd){ .fd = -1 };
pfds[i] = (os_poll_file_handle){ .fd = -1 };
out[(*nevents)++] = (__wasi_event_t){
.userdata = s->userdata,
.error = __WASI_ENOSYS,
Expand Down Expand Up @@ -2270,7 +2275,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
__wasi_filesize_t nbytes = 0;
if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) {
int l;
if (ioctl(fos[i]->file_handle, FIONREAD, &l) == 0)
if (os_ioctl(fos[i]->file_handle, FIONREAD, &l) == 0)
nbytes = (__wasi_filesize_t)l;
}
if ((pfds[i].revents & POLLNVAL) != 0) {
Expand Down Expand Up @@ -2436,7 +2441,7 @@ wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen)
if (addr->kind == IPv4) {
const char *format = "%u.%u.%u.%u";

assert(buflen >= 16);
bh_assert(buflen >= 16);

snprintf(buf, buflen, format, addr->addr.ip4.addr.n0,
addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2,
Expand All @@ -2448,14 +2453,13 @@ wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen)
const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x";
__wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr;

assert(buflen >= 40);
bh_assert(buflen >= 40);

snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3,
ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3);

return true;
}

return false;
}

Expand Down Expand Up @@ -2562,9 +2566,11 @@ wasi_ssp_sock_connect(wasm_exec_env_t exec_env, struct fd_table *curfds,
}

error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0);
if (error != __WASI_ESUCCESS)
if (error != __WASI_ESUCCESS) {
return error;
}

/* Consume __wasi_addr_t */
ret = blocking_op_socket_connect(exec_env, fo->file_handle, buf,
addr->kind == IPv4 ? addr->addr.ip4.port
: addr->addr.ip6.port);
Expand Down Expand Up @@ -2713,10 +2719,10 @@ wasi_ssp_sock_open(wasm_exec_env_t exec_env, struct fd_table *curfds,
}

if (SOCKET_DGRAM == socktype) {
assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM);
bh_assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM);
}
else {
assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM);
bh_assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM);
}

// TODO: base rights and inheriting rights ?
Expand Down Expand Up @@ -2834,6 +2840,9 @@ wasmtime_ssp_sock_recv_from(wasm_exec_env_t exec_env, struct fd_table *curfds,
return error;
}

wasi_addr_to_bh_sockaddr(src_addr, &sockaddr);

/* Consume bh_sockaddr_t instead of __wasi_addr_t */
ret = blocking_op_socket_recv_from(exec_env, fo->file_handle, buf, buf_len,
0, &sockaddr);
fd_object_release(exec_env, fo);
Expand Down Expand Up @@ -2899,6 +2908,7 @@ wasmtime_ssp_sock_send_to(wasm_exec_env_t exec_env, struct fd_table *curfds,

wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr);

/* Consume bh_sockaddr instead of __wasi_addr_t */
ret = blocking_op_socket_send_to(exec_env, fo->file_handle, buf, buf_len, 0,
&sockaddr);
fd_object_release(exec_env, fo);
Expand Down Expand Up @@ -2930,8 +2940,10 @@ wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds,
__wasi_errno_t
wasmtime_ssp_sched_yield(void)
{
#ifdef BH_PLATFORM_WINDOWS
#if defined(BH_PLATFORM_WINDOWS)
SwitchToThread();
#elif defined(BH_PLATFORM_ZEPHYR)
k_yield();
#else
if (sched_yield() < 0)
return convert_errno(errno);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ random_buf(void *buf, size_t len)
return ret ? __WASI_EINVAL : __WASI_ESUCCESS;
}

#elif defined(BH_PLATFORM_ZEPHYR)
#include <zephyr/random/random.h>
// Maybe having an OS abstraction api would be a good idea
// because every platform is implementing this function.
// we could have a function like `os_random_buf`
// and call `os_random_buf.` in the SSP wrapper `random_buf`.

__wasi_errno_t
random_buf(void *buf, size_t len)
{
sys_rand_get(buf, len);
return __WASI_ESUCCESS;
}

#else

static int urandom = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,16 @@
#define CONFIG_HAS_GETRANDOM 0
#endif

#if defined(__CloudABI__) || defined(BH_PLATFORM_FREERTOS)
#if defined(__CloudABI__) || defined(BH_PLATFORM_FREERTOS) \
|| defined(BH_PLATFORM_ZEPHYR)
#define CONFIG_HAS_CAP_ENTER 1
#else
#define CONFIG_HAS_CAP_ENTER 0
#endif

#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__EMSCRIPTEN__) \
&& !defined(ESP_PLATFORM) && !defined(DISABLE_CLOCK_NANOSLEEP) \
&& !defined(BH_PLATFORM_FREERTOS)
&& !defined(BH_PLATFORM_FREERTOS) && !defined(BH_PLATFORM_ZEPHYR)
#define CONFIG_HAS_CLOCK_NANOSLEEP 1
#else
#define CONFIG_HAS_CLOCK_NANOSLEEP 0
Expand All @@ -63,7 +64,8 @@
#endif

#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) && !defined(_WIN32) \
&& !defined(__COSMOPOLITAN__) && !defined(BH_PLATFORM_FREERTOS)
&& !defined(__COSMOPOLITAN__) && !defined(BH_PLATFORM_FREERTOS) \
&& !defined(BH_PLATFORM_ZEPHYR)
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
#else
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0
Expand Down
Loading

0 comments on commit 0464262

Please sign in to comment.