Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 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_populate_preopens
__wasilibc_pthread_self
__wasilibc_random
__wasilibc_read
__wasilibc_read_poll
__wasilibc_rename_newat
__wasilibc_rename_oldat
__wasilibc_reset_preopens
Expand All @@ -350,9 +351,11 @@ __wasilibc_tell
__wasilibc_unlinkat
__wasilibc_unspecified_addr
__wasilibc_utimens
__wasilibc_waitable_block_on
__wasilibc_wasi_family_to_libc
__wasilibc_wasi_to_sockaddr
__wasilibc_write
__wasilibc_write_poll
__wasm_call_dtors
__wcscoll_l
__wcsftime_l
Expand Down
42 changes: 28 additions & 14 deletions libc-bottom-half/cloudlibc/src/libc/poll/poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,20 +372,30 @@ static int poll_impl(struct pollfd *fds, size_t nfds, int timeout) {
goto out;
}


if (events & POLLRDNORM) {
// TODO(wasip3): use `get_read_stream` and use that I/O to do something.
// Requires a lot more integration with nonblocking I/O to get that
// working.
errno = EOPNOTSUPP;
goto out;
if (entry->vtable->get_read_stream) {
wasi_read_t read;
if (entry->vtable->get_read_stream(entry->data, &read) < 0)
goto out;
if (__wasilibc_read_poll(read.state, &state) < 0)
goto out;
} else {
errno = EOPNOTSUPP;
goto out;
}
}

if (events & POLLWRNORM) {
// TODO(wasip3): use `get_write_stream` to implement this (see
// `POLLRDNORM` above).
errno = EOPNOTSUPP;
goto out;
if (entry->vtable->get_write_stream) {
wasi_write_t write;
if (entry->vtable->get_write_stream(entry->data, &write) < 0)
goto out;
if (__wasilibc_write_poll(write.state, &state) < 0)
goto out;
} else {
errno = EOPNOTSUPP;
goto out;
}
}
}

Expand Down Expand Up @@ -451,10 +461,14 @@ static int poll_impl(struct pollfd *fds, size_t nfds, int timeout) {
if (p->waitable != event.waitable)
continue;
state.pollfd = p->pollfd;
// Clear the `waitable` since this event has fired and it doesn't need
// to be join'd to 0 below. Then invoke the custom callback originally
// added for this which will handle any necessary completion logic and
// updating `state.pollfd` with various events.
// Remove this waitable from the `waitable-set` as the `ready`
// operation might end up deleting the handle. Set the list here to 0
// so it's not removed down below.
//
// Then invoke the custom callback originally added for this
// which will handle any necessary completion logic and updating
// `state.pollfd` with various events.
wasip3_waitable_join(p->waitable, 0);
p->waitable = 0;
p->ready(p->ready_data, &state, &event);
}
Expand Down
2 changes: 0 additions & 2 deletions libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
// SPDX-License-Identifier: BSD-2-Clause

#include <common/time.h>

#include <sys/select.h>

#include <wasi/api.h>
#include <errno.h>
#include <poll.h>
Expand Down
49 changes: 39 additions & 10 deletions libc-bottom-half/headers/private/wasi/descriptor_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,49 @@
#ifndef __wasip1__
#include <assert.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <wasi/poll.h>

#ifdef __wasip3__

/// The stream is complete and no further operations are allowed on it.
#define WASIP3_IO_DONE (1 << 0)
/// An I/O operation, be it a read or write, is in flight.
#define WASIP3_IO_INPROGRESS (1 << 1)
/// The in-flight I/O operation is a zero-length operation. This means that if
/// it's finished we expect that the next operation finishes immediately.
#define WASIP3_IO_ZERO_INPROGRESS (1 << 2)
/// A zero-sized in-flight I/O operation just finished so the next I/O op
/// should finish immediately. If it doesn't it'll turn on the next flag.
#define WASIP3_IO_SHOULD_BE_READY (1 << 3)
/// This stream isn't compatible with zero-length reads/writes signaling
/// readiness, so libc must buffer data internally for reads/writes.
#define WASIP3_IO_MUST_BUFFER (1 << 4)

/// Helper structure to package up state related to a wasip3 `stream<u8>`.
///
/// This is used by various helpers to coordinate reading/writing/etc on a
/// stream. This simultaneously represents both readers and writers.
typedef struct wasip3_io_state_t {
uint32_t stream;
bool done;
/// Bitset of `WASIP3_IO_*` flags.
uint32_t flags;
/// Malloc'd buffer used for reads/writes. NULL if not present.
uint8_t *buf;
/// Start of `buf` that has data in-flight or ready.
size_t buf_start;
/// End of `buf` that has data in-flight or ready.
size_t buf_end;
} wasip3_io_state_t;

/// Initializes `state` with the `stream` provided.
static inline void wasip3_io_state_init(wasip3_io_state_t *state,
uint32_t stream) {
assert(stream != 0);
memset(state, 0, sizeof(*state));
state->stream = stream;
state->done = false;
}

/// Tests whether `state` has been initialized with a stream yet.
Expand All @@ -37,22 +60,26 @@ static inline bool wasip3_io_state_present(wasip3_io_state_t *state) {
///
/// Internally the stream must be a reader-half of a `stream<u8>`.
static inline void wasip3_read_state_close(wasip3_io_state_t *state) {
if (state->stream != 0) {
if (state->flags & WASIP3_IO_INPROGRESS)
filesystem_stream_u8_cancel_read(state->stream);
if (state->buf)
free(state->buf);
if (state->stream != 0)
filesystem_stream_u8_drop_readable(state->stream);
state->stream = 0;
}
state->done = false;
memset(state, 0, sizeof(*state));
}

/// Closes out the streams/etc internal to `state`.
///
/// Internally the stream must be a writer-half of a `stream<u8>`.
static inline void wasip3_write_state_close(wasip3_io_state_t *state) {
if (state->stream != 0) {
if (state->flags & WASIP3_IO_INPROGRESS)
filesystem_stream_u8_cancel_write(state->stream);
if (state->buf)
free(state->buf);
if (state->stream != 0)
filesystem_stream_u8_drop_writable(state->stream);
state->stream = 0;
}
state->done = false;
memset(state, 0, sizeof(*state));
}
#endif

Expand Down Expand Up @@ -195,6 +222,7 @@ typedef struct descriptor_vtable_t {
/// and `get_write_stream`, if present, to handle `POLL{RD,WR}NORM` events.
int (*poll_register)(void *, poll_state_t *state, short events);

#ifdef __wasip2__
/// Invoked when `poll` has already run and detected that this object was
/// ready. The `events` provided are the same as those provided to
/// `__wasilibc_poll_add` originally. This function should call
Expand All @@ -204,6 +232,7 @@ typedef struct descriptor_vtable_t {
/// If this function is not provided then `events` will automatically
/// be placed into the `revents` field of `pollfd`.
int (*poll_finish)(void *, poll_state_t *state, short events);
#endif // __wasip2__
} descriptor_vtable_t;

/// A "fat pointer" which is placed inside of the descriptor table.
Expand Down
13 changes: 13 additions & 0 deletions libc-bottom-half/headers/private/wasi/file_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <errno.h>
#include <fcntl.h>
#include <wasi/descriptor_table.h>
#include <wasi/poll.h>
#include <wasi/wasip2.h>

#ifdef __wasip2__
Expand Down Expand Up @@ -119,6 +120,18 @@ dir_entry_type_to_d_type(filesystem_descriptor_type_t *ty) {
}
}

#ifndef __wasip2__
/// Starts the process of `poll` for `iostate` assuming it's backed by a
/// readable stream.
///
/// This will handle all the internal logic for zero-length reads/writes/etc
/// and add to `state` as necessary.
int __wasilibc_read_poll(wasip3_io_state_t *iostate, poll_state_t *state);

/// Write dual of `__wasilibc_read_poll`.
int __wasilibc_write_poll(wasip3_io_state_t *iostate, poll_state_t *state);
#endif // !__wasip2__

#endif // __wasip2__ || __wasip3__

#endif // __wasi_file_utils_h
14 changes: 13 additions & 1 deletion libc-bottom-half/headers/private/wasi/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,25 @@ typedef struct {
wasip3_subtask_t subtask;
#endif
} tcp_socket_state_connecting_t;

/// The `stream` in `tcp_socket_state_listening_t` is finished and should not
/// be read again.
#define TCP_LISTENING_DONE (1 << 0)
/// There is an active read on `stream` which has yet to complete.
#define TCP_LISTENING_ACCEPTING (1 << 1)
/// The `accept_result` field is valid and ready to be processed.
#define TCP_LISTENING_ACCEPT_READY (1 << 2)

typedef struct {
#ifdef __wasip2__
int dummy;
#else
// The `stream<tcp-socket>` that this is reading to receive accepted sockets.
sockets_stream_own_tcp_socket_t stream;
bool done;
/// In-flight result of the read of `stream`.
sockets_own_tcp_socket_t accept_result;
/// Bitset of `TCP_LISTENING_*`.
uint32_t flags;
#endif
} tcp_socket_state_listening_t;

Expand Down
8 changes: 8 additions & 0 deletions libc-bottom-half/headers/private/wasi/wasip3_block.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@

typedef wasip3_waitable_status_t (*wasip3_cancel_t)(uint32_t);

/// Wait at most `timeout` duration for `waitable` to become ready.
///
/// If `timeout` is 0 this will wait indefinitely. Returns `true` if `waitable`
/// has become ready. Returns `false` if `timeout` elapsed. Upon returning
/// `true` the `event` field is filled in.
bool __wasilibc_waitable_block_on(uint32_t waitable, wasip3_event_t *event,
monotonic_clock_duration_t timeout);

// Waits for a subtask to return
void __wasilibc_subtask_block_on_and_drop(wasip3_subtask_t subtask);

Expand Down
Loading