Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
24dac6d
working stdout
cpetig Dec 28, 2025
e741d5f
clang-format
cpetig Dec 28, 2025
9cb53d8
working file existance
cpetig Dec 30, 2025
faccdc0
file read stub
cpetig Dec 30, 2025
fe78c70
proper file reading
cpetig Dec 30, 2025
c7e45ac
working file read
cpetig Dec 30, 2025
3d915cf
file stat
cpetig Jan 2, 2026
b681470
wait on stream
cpetig Jan 2, 2026
357b197
small read correction
cpetig Jan 3, 2026
c44f03f
tcp skeleton
cpetig Jan 3, 2026
235bc16
more tcp implementation
cpetig Jan 3, 2026
1e95b05
separate file utils, add pipe
cpetig Jan 3, 2026
0bc6278
factor out block_on
cpetig Jan 4, 2026
ac6b123
format
cpetig Jan 4, 2026
1f9654a
connect
cpetig Jan 4, 2026
942d6c7
initial poll implementation
cpetig Jan 4, 2026
c902e17
correct timeout handling
cpetig Jan 4, 2026
77f4c46
dummy setsockopt for now
cpetig Jan 4, 2026
9911476
poll on tcp
cpetig Jan 4, 2026
2308b9e
only cancel active timeout
cpetig Jan 4, 2026
5eda1b7
proper tcp socket free
cpetig Jan 4, 2026
e677d0b
revised write/read interface
cpetig Jan 4, 2026
23b327c
reimplementation complete
cpetig Jan 4, 2026
b27f8be
remove outdated code
cpetig Jan 4, 2026
39e1025
feels more right, but didn't fix the missing write ready
cpetig Jan 4, 2026
c5f6782
delay creation of read/write streams to after connect (otherwise even…
cpetig Jan 5, 2026
6ad7f2f
refresh p2 bindings (helps ci)
cpetig Jan 5, 2026
f357710
correct expected
cpetig Jan 5, 2026
834299d
next try to fix expected
cpetig Jan 5, 2026
ad25962
format
cpetig Jan 5, 2026
212da89
handle blocking writes
cpetig Jan 5, 2026
1359a0e
small correction in write
cpetig Jan 6, 2026
bbace4f
post merge fixes
cpetig Jan 6, 2026
53f4b9b
remove some unintentional changes
cpetig Jan 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions expected/wasm32-wasip3/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ __wasilibc_open_nomode
__wasilibc_populate_preopens
__wasilibc_pthread_self
__wasilibc_random
__wasilibc_read3
__wasilibc_rename_newat
__wasilibc_rename_oldat
__wasilibc_reset_preopens
Expand All @@ -344,6 +345,7 @@ __wasilibc_stat
__wasilibc_tell
__wasilibc_unlinkat
__wasilibc_utimens
__wasilibc_write3
__wasm_call_dtors
__wcscoll_l
__wcsftime_l
Expand Down Expand Up @@ -1003,6 +1005,7 @@ optopt
optreset
pathconf
perror
pipe
poll
posix_close
posix_fadvise
Expand Down Expand Up @@ -1472,7 +1475,9 @@ wasip3_list_u8_free
wasip3_option_string_free
wasip3_string_dup
wasip3_string_free
wasip3_string_from_c
wasip3_string_set
wasip3_subtask_block_on
wasip3_subtask_cancel
wasip3_subtask_drop
wasip3_task_cancel
Expand Down
2 changes: 2 additions & 0 deletions libc-bottom-half/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ if (WASI STREQUAL "p3")
list(APPEND bottom_half_sources
sources/wasip3.c
sources/wasip3_file.c
sources/wasip3_file_utils.c
sources/wasip3_pipe.c
sources/wasip3_stdio.c
sources/wasip3_tcp.c
sources/wasip3_udp.c
Expand Down
4 changes: 3 additions & 1 deletion libc-bottom-half/cloudlibc/src/common/errors.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <wasi/api.h>

#ifdef __wasip2__
#if defined(__wasip2__) || defined(__wasip3__)
#include <errno.h>
#include <stdlib.h>

Expand All @@ -9,9 +9,11 @@ static void translate_error(filesystem_error_code_t error) {
case FILESYSTEM_ERROR_CODE_ACCESS:
errno = EACCES;
break;
#ifdef __wasip2__
case FILESYSTEM_ERROR_CODE_WOULD_BLOCK:
errno = EAGAIN;
break;
#endif
case FILESYSTEM_ERROR_CODE_ALREADY:
errno = EALREADY;
break;
Expand Down
32 changes: 28 additions & 4 deletions libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include <common/errors.h>
#endif

#ifdef __wasip3__
#include <wasi/sockets_utils.h>
#endif

#ifdef __wasip1__
static_assert(O_APPEND == __WASI_FDFLAGS_APPEND, "Value mismatch");
static_assert(O_DSYNC == __WASI_FDFLAGS_DSYNC, "Value mismatch");
Expand Down Expand Up @@ -87,7 +91,7 @@ int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) {
return -1;
}
return newfd;
#elif defined(__wasip2__)
#elif defined(__wasip2__) || defined(__wasip3__)
// Set up path flags
filesystem_path_flags_t lookup_flags = 0;
if ((oflag & O_NOFOLLOW) == 0)
Expand Down Expand Up @@ -140,6 +144,7 @@ int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) {
return -1;

// Construct a WASI string for the path
#ifdef __wasip2__
wasip2_string_t path2;
if (wasip2_string_from_c(path, &path2) < 0)
return -1;
Expand All @@ -162,9 +167,28 @@ int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) {
// Update the descriptor table with the new handle
return __wasilibc_add_file(new_handle, oflag);
#elif defined(__wasip3__)
// TODO(wasip3)
errno = ENOTSUP;
return -1;
wasip3_string_t path2;
if (wasip3_string_from_c(path, &path2) < 0)
return -1;

// Open the file, yielding a new handle
filesystem_method_descriptor_open_at_args_t args;
args.self = file_handle;
args.flags = lookup_flags;
args.path = path2;
args.open_flags = open_flags;
args.path_flags = fs_flags;
filesystem_result_own_descriptor_error_code_t result;
wasip3_subtask_status_t status = filesystem_method_descriptor_open_at(&args, &result);
wasip3_subtask_block_on(status);
if (result.is_err) {
translate_error(result.val.err);
return -1;
}

// Update the descriptor table with the new handle
return __wasilibc_add_file(result.val.ok, oflag);
#endif
#else
# error "Unsupported WASI version"
#endif
Expand Down
145 changes: 142 additions & 3 deletions libc-bottom-half/cloudlibc/src/libc/poll/poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,150 @@ static int poll_impl(struct pollfd *fds, size_t nfds, int timeout) {
}

#elif defined(__wasip3__)
#include <stdlib.h>

typedef struct {
wasip3_subtask_status_t waitable;
struct pollfd *pollfd;
} state3_t;

static int poll_impl(struct pollfd *fds, size_t nfds, int timeout) {
// TODO(wasip3)
errno = ENOTSUP;
return -1;
for (size_t i = 0; i < nfds; ++i) {
fds[i].revents = 0;
}

int return_value = 0;
size_t max_pollables = (2 * nfds) + 1;
state3_t states[max_pollables];
size_t pollable_count = 0;
wasip3_subtask_status_t timeout_subtask;

wasip3_waitable_set_t set = wasip3_waitable_set_new();

for (size_t i = 0; i < nfds; ++i) {
struct pollfd *pollfd = fds + i;
if (pollfd->fd < 0)
continue;
descriptor_table_entry_t *entry = descriptor_table_get_ref(pollfd->fd);
if (!entry) {
errno = EBADF;
return_value = -1;
goto cleanup_and_exit;
}

// Without a custom registration handle read/write readiness
// below, but everything else is unsupported.
if (pollfd->events & ~(POLLRDNORM | POLLWRNORM)) {
errno = EOPNOTSUPP;
return_value = -1;
goto cleanup_and_exit;
}

if (pollfd->events & POLLRDNORM) {
if (entry->vtable->read3) {
waitable_t input;
wasip3_waitable_status_t status;
if (entry->vtable->read3(entry->data, 0, 0, &input, &status, NULL) < 0) {
return_value = -1;
goto cleanup_and_exit;
}
// = filesystem_stream_u8_read(input, 0, 0);
if (status != WASIP3_WAITABLE_STATUS_BLOCKED) {
pollfd->revents |= POLLRDNORM;
++return_value;
} else if (!return_value) {
states[pollable_count].waitable = input;
states[pollable_count].pollfd = pollfd;
++pollable_count;
wasip3_waitable_join(input, set);
}
} else {
errno = EOPNOTSUPP;
return_value = -1;
goto cleanup_and_exit;
}
}

if (pollfd->events & POLLWRNORM) {
if (entry->vtable->write3) {
waitable_t input;
wasip3_waitable_status_t status;
if (entry->vtable->write3(entry->data, 0, 0, &input, &status, NULL) < 0){
return_value = -1;
goto cleanup_and_exit;
}
if (status != WASIP3_WAITABLE_STATUS_BLOCKED) {
pollfd->revents |= POLLWRNORM;
++return_value;
} else if (!return_value) {
states[pollable_count].waitable = input;
states[pollable_count].pollfd = pollfd;
++pollable_count;
wasip3_waitable_join(input, set);
}
} else {
errno = EOPNOTSUPP;
return_value = -1;
goto cleanup_and_exit;
}
}
}

if (return_value) goto cleanup_and_exit;

if (timeout >= 0) {
timeout_subtask = monotonic_clock_wait_for(
((monotonic_clock_duration_t)timeout) * 1000000);
if (WASIP3_SUBTASK_STATE(timeout_subtask) == WASIP3_SUBTASK_RETURNED) {
goto cleanup_and_exit;
}
assert(WASIP3_SUBTASK_STATE(timeout_subtask) == WASIP3_SUBTASK_STARTED);
wasip3_waitable_join(WASIP3_SUBTASK_HANDLE(timeout_subtask), set);
}

wasip3_event_t event;
wasip3_waitable_set_wait(set, &event);
return_value = 0;
switch (event.event) {
case WASIP3_EVENT_STREAM_READ:
for (size_t i=0; i<pollable_count; ++i) {
if (states[i].waitable == event.waitable) {
states[i].pollfd->revents |= POLLRDNORM;
++return_value;
break;
}
}
break;
case WASIP3_EVENT_STREAM_WRITE:
for (size_t i=0; i<pollable_count; ++i) {
if (states[i].waitable == event.waitable) {
states[i].pollfd->revents |= POLLWRNORM;
++return_value;
break;
}
}
break;
case WASIP3_EVENT_SUBTASK:
assert(event.waitable == WASIP3_SUBTASK_HANDLE(timeout_subtask));
break;
default:
abort();
}
if (timeout >= 0) {
wasip3_waitable_join(WASIP3_SUBTASK_HANDLE(timeout_subtask), 0);
if (return_value>0)
wasip3_subtask_cancel(WASIP3_SUBTASK_HANDLE(timeout_subtask));
}

//repeat wasip3_waitable_set_poll(set, &event); ?

cleanup_and_exit:
for (size_t i=0; i<pollable_count; ++i) {
wasip3_waitable_join(states[i].waitable, 0);
}
wasip3_waitable_set_drop(set);

return return_value;
}

#else
Expand Down
6 changes: 1 addition & 5 deletions libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,12 @@ int fstat(int fildes, struct stat *buf) {
}
to_public_stat(&internal_stat, buf);
return 0;
#elif defined(__wasip2__)
#elif defined(__wasip2__) || defined(__wasip3__)
// Translate the file descriptor to an internal handle
descriptor_table_entry_t *entry = descriptor_table_get_ref(fildes);
if (!entry)
return -1;
return entry->vtable->fstat(entry->data, buf);
#elif defined(__wasip3__)
// TODO(wasip3)
errno = ENOTSUP;
return -1;
#else
# error "Unsupported WASI version"
#endif
Expand Down
32 changes: 29 additions & 3 deletions libc-bottom-half/cloudlibc/src/libc/unistd/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,35 @@ ssize_t read(int fildes, void *buf, size_t nbyte) {
*off += contents.len;
return contents.len;
#elif defined(__wasip3__)
// TODO(wasip3)
errno = ENOTSUP;
return -1;
off_t *off;
waitable_t waitable;
wasip3_waitable_status_t status;
if (__wasilibc_read3(fildes, buf, nbyte, &waitable, &status, &off) < 0)
return -1;
if (status == WASIP3_WAITABLE_STATUS_BLOCKED) {
wasip3_waitable_set_t set = wasip3_waitable_set_new();
wasip3_waitable_join(waitable, set);
wasip3_event_t event;
wasip3_waitable_set_wait(set, &event);
assert(event.event == WASIP3_EVENT_STREAM_READ);
assert(event.waitable == waitable);
// remove from set
wasip3_waitable_join(waitable, 0);
wasip3_waitable_set_drop(set);
ssize_t bytes_read = event.code;
if (off)
*off += bytes_read;
return bytes_read;
} else if (WASIP3_WAITABLE_STATE(status) == WASIP3_WAITABLE_COMPLETED) {
ssize_t bytes_read = WASIP3_WAITABLE_COUNT(status);
if (off)
*off += bytes_read;
return bytes_read;
} else if (WASIP3_WAITABLE_STATE(status) == WASIP3_WAITABLE_DROPPED) {
return 0;
} else {
abort();
}
#else
# error "Unsupported WASI version"
#endif
Expand Down
31 changes: 28 additions & 3 deletions libc-bottom-half/cloudlibc/src/libc/unistd/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <errno.h>
#include <unistd.h>
#include <wasi/api.h>
#include <stdlib.h>

#ifndef __wasip1__
#include <wasi/descriptor_table.h>
Expand Down Expand Up @@ -72,9 +73,33 @@ ssize_t write(int fildes, const void *buf, size_t nbyte) {
*off += contents.len;
return contents.len;
#elif defined(__wasip3__)
// TODO(wasip3)
errno = ENOTSUP;
return -1;
off_t *off;
waitable_t output_stream;
wasip3_waitable_status_t status;
if (__wasilibc_write3(fildes, buf, nbyte, &output_stream, &status, &off) < 0)
return -1;
if (status == WASIP3_WAITABLE_STATUS_BLOCKED) {
wasip3_waitable_set_t set = wasip3_waitable_set_new();
wasip3_waitable_join(output_stream, set);
wasip3_event_t event;
wasip3_waitable_set_wait(set, &event);
assert(event.event == WASIP3_EVENT_STREAM_WRITE);
assert(event.waitable == output_stream);
// remove from set
wasip3_waitable_join(output_stream, 0);
wasip3_waitable_set_drop(set);
ssize_t bytes_written = event.code;
if (off)
*off += bytes_written;
return bytes_written;
} else if (WASIP3_WAITABLE_STATE(status) == WASIP3_WAITABLE_COMPLETED) {
ssize_t bytes_written = WASIP3_WAITABLE_COUNT(status);
if (off)
*off += bytes_written;
return bytes_written;
} else {
abort();
}
#else
# error "Unknown WASI version"
#endif
Expand Down
Loading
Loading