diff --git a/expected/wasm32-wasip3/defined-symbols.txt b/expected/wasm32-wasip3/defined-symbols.txt index 523c3b58d..b7e6209b4 100644 --- a/expected/wasm32-wasip3/defined-symbols.txt +++ b/expected/wasm32-wasip3/defined-symbols.txt @@ -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 @@ -344,6 +345,7 @@ __wasilibc_stat __wasilibc_tell __wasilibc_unlinkat __wasilibc_utimens +__wasilibc_write3 __wasm_call_dtors __wcscoll_l __wcsftime_l @@ -1472,6 +1474,7 @@ 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 diff --git a/libc-bottom-half/CMakeLists.txt b/libc-bottom-half/CMakeLists.txt index d0aca4732..294b64bf0 100644 --- a/libc-bottom-half/CMakeLists.txt +++ b/libc-bottom-half/CMakeLists.txt @@ -164,6 +164,7 @@ if (WASI STREQUAL "p3") list(APPEND bottom_half_sources sources/wasip3.c sources/wasip3_file.c + sources/wasip3_file_utils.c sources/wasip3_stdio.c sources/wasip3_subtask.c sources/wasip3_tcp.c diff --git a/libc-bottom-half/cloudlibc/src/common/errors.h b/libc-bottom-half/cloudlibc/src/common/errors.h index cee2b56bb..ecabc4301 100644 --- a/libc-bottom-half/cloudlibc/src/common/errors.h +++ b/libc-bottom-half/cloudlibc/src/common/errors.h @@ -1,6 +1,6 @@ #include -#ifdef __wasip2__ +#if defined(__wasip2__) || defined(__wasip3__) #include #include @@ -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; diff --git a/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c b/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c index 0f6b5047a..bb138aca8 100644 --- a/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c +++ b/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c @@ -16,6 +16,10 @@ #include #endif +#ifdef __wasip3__ +#include +#endif + #ifdef __wasip1__ static_assert(O_APPEND == __WASI_FDFLAGS_APPEND, "Value mismatch"); static_assert(O_DSYNC == __WASI_FDFLAGS_DSYNC, "Value mismatch"); @@ -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) @@ -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; @@ -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 path3; + if (wasip3_string_from_c(path, &path3) < 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 = path3; + 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 diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c b/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c index f48e372b4..1305686a5 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c @@ -29,7 +29,7 @@ off_t __lseek(int fildes, off_t offset, int whence) { return -1; } return new_offset; -#elif defined(__wasip2__) +#elif defined(__wasip2__) || defined(__wasip3__) // Look up a stream for fildes descriptor_table_entry_t *entry = descriptor_table_get_ref(fildes); if (!entry) @@ -39,10 +39,6 @@ off_t __lseek(int fildes, off_t offset, int whence) { return -1; } return entry->vtable->seek(entry->data, offset, whence); -#elif defined(__wasip3__) - // TODO(wasip3) - errno = ENOTSUP; - return -1; #else # error "Unknown WASI version" #endif diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/read.c b/libc-bottom-half/cloudlibc/src/libc/unistd/read.c index eb842976f..ec1f18f35 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/read.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/read.c @@ -53,9 +53,7 @@ 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; + return __wasilibc_read3(fildes, buf, nbyte); #else # error "Unsupported WASI version" #endif diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/write.c b/libc-bottom-half/cloudlibc/src/libc/unistd/write.c index 0f2f9275f..d7287fd3f 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/write.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/write.c @@ -72,9 +72,7 @@ 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; + return __wasilibc_write3(fildes, buf, nbyte); #else # error "Unknown WASI version" #endif diff --git a/libc-bottom-half/headers/private/wasi/descriptor_table.h b/libc-bottom-half/headers/private/wasi/descriptor_table.h index 217728215..99e57fb39 100644 --- a/libc-bottom-half/headers/private/wasi/descriptor_table.h +++ b/libc-bottom-half/headers/private/wasi/descriptor_table.h @@ -8,6 +8,11 @@ #include #include +#ifdef __wasip3__ +// create an alias to distinguish the handle type in the API +typedef uint32_t waitable_t; +#endif + /** * Operations that are required of all descriptors registered as file * descriptors. @@ -37,6 +42,12 @@ typedef struct descriptor_vtable_t { /// Same as `get_read_stream`, but for output streams. int (*get_write_stream)(void*, streams_borrow_output_stream_t*, off_t**, poll_own_pollable_t**); #endif +#ifdef __wasip3__ + /// Start an asynchronous read or write, returns zero on success. + /// Stores the waitable, status and offset location. + int (*read3)(void*, void *buf, size_t nbyte, waitable_t *waitable, wasip3_waitable_status_t *out, off_t**); + int (*write3)(void*, void const *buf, size_t nbyte, waitable_t *waitable, wasip3_waitable_status_t *out, off_t**); +#endif /// Sets the nonblocking flag for this object to the specified value. int (*set_blocking)(void*, bool); diff --git a/libc-bottom-half/headers/private/wasi/file_utils.h b/libc-bottom-half/headers/private/wasi/file_utils.h index 5e04d5394..35ef11ced 100644 --- a/libc-bottom-half/headers/private/wasi/file_utils.h +++ b/libc-bottom-half/headers/private/wasi/file_utils.h @@ -3,14 +3,16 @@ #include -#ifdef __wasip2__ +#if defined(__wasip2__) || defined(__wasip3__) #include #include #include #include #include #include +#endif +#ifdef __wasip2__ /// Handles a `wasi:io/streams.stream-error` for a `read`-style operation. /// /// If the error indicates "closed" then 0 is returned to mean EOF. Otherwise @@ -46,7 +48,9 @@ static int wasip2_handle_write_error(streams_stream_error_t error) { // Returns 0 if `s` is valid utf-8. // Returns -1 and sets errno to `ENOENT` if `s` is not valid utf-8. int wasip2_string_from_c(const char *s, wasip2_string_t* out); +#endif +#if defined(__wasip2__) || defined(__wasip3__) // Succeed only if fd is bound to a file handle in the descriptor table static int fd_to_file_handle(int fd, filesystem_borrow_descriptor_t* result) { descriptor_table_entry_t* entry = descriptor_table_get_ref(fd); @@ -58,7 +62,9 @@ static int fd_to_file_handle(int fd, filesystem_borrow_descriptor_t* result) { } return entry->vtable->get_file(entry->data, result); } +#endif +#ifdef __wasip2__ // Gets an `output-stream` borrow from the `fd` provided. int __wasilibc_write_stream(int fd, streams_borrow_output_stream_t *out, @@ -96,4 +102,13 @@ static unsigned dir_entry_type_to_d_type(filesystem_descriptor_type_t ty) { #endif +#ifdef __wasip3__ +#include + +int wasip3_string_from_c(const char *s, wasip3_string_t* out); + +ssize_t __wasilibc_write3(int fildes, void const *buf, size_t nbyte); +ssize_t __wasilibc_read3(int fildes, void *buf, size_t nbyte); +#endif + #endif diff --git a/libc-bottom-half/sources/wasip3_file.c b/libc-bottom-half/sources/wasip3_file.c index 88639497f..8e185c27a 100644 --- a/libc-bottom-half/sources/wasip3_file.c +++ b/libc-bottom-half/sources/wasip3_file.c @@ -2,11 +2,179 @@ #include #ifdef __wasip3__ +#include +#include +#include +#include +#include +#include + +typedef struct { + filesystem_own_descriptor_t file_handle; + off_t offset; + int oflag; + filesystem_tuple2_stream_u8_future_result_void_error_code_t read; + filesystem_stream_u8_writer_t write; + wasip3_subtask_status_t write_task; + filesystem_result_void_error_code_t write_error; +} file3_t; + +static void file_close_streams(void *data) { + file3_t *file = (file3_t *)data; + if (file->read.f0!=0) { + filesystem_stream_u8_drop_readable(file->read.f0); + filesystem_future_result_void_error_code_drop_readable(file->read.f1); + } + if (file->write!=0) { + sockets_stream_u8_drop_writable(file->write); + wasip3_subtask_cancel(file->write_task); + } +} + +static void file_free(void *data) { + file3_t *file = (file3_t *)data; + file_close_streams(data); + filesystem_descriptor_drop_own(file->file_handle); + free(file); +} + +static int file_get_file(void *data, filesystem_borrow_descriptor_t *out_file) { + file3_t *file = (file3_t *)data; + *out_file = filesystem_borrow_descriptor(file->file_handle); + return 0; +} + +static int file_fstat(void *data, struct stat *buf) { + file3_t *file = (file3_t *)data; + // Get the metadata hash for the file descriptor + filesystem_result_metadata_hash_value_error_code_t result; + wasip3_subtask_status_t status = filesystem_method_descriptor_metadata_hash( + filesystem_borrow_descriptor(file->file_handle), &result); + wasip3_subtask_block_on(status); + if (result.is_err) { + translate_error(result.val.err); + return -1; + } + + // Get the file metadata + filesystem_result_descriptor_stat_error_code_t stat_result; + status = filesystem_method_descriptor_stat( + filesystem_borrow_descriptor(file->file_handle), &stat_result); + wasip3_subtask_block_on(status); + if (stat_result.is_err) { + translate_error(stat_result.val.err); + return -1; + } + + // Convert the internal data to an external struct + to_public_stat(&result.val.ok, &stat_result.val.ok, buf); + return 0; +} + +static int file_seek_end(file3_t *file) { + filesystem_result_descriptor_stat_error_code_t result; + wasip3_subtask_status_t status = filesystem_method_descriptor_stat( + filesystem_borrow_descriptor(file->file_handle), &result); + wasip3_subtask_block_on(status); + if (result.is_err) { + translate_error(result.val.err); + return -1; + } + file->offset = (off_t)result.val.ok.size; + return 0; +} + +static off_t file_seek(void *data, off_t offset, int whence) { + file3_t *file = (file3_t *)data; + + // If this file is in append mode, reset our knowledge of the current cursor + // to the current end of the file. + if ((file->oflag & O_APPEND) && file_seek_end(file) < 0) + return -1; + + off_t result; + switch (whence) { + case SEEK_SET: + result = offset; + break; + case SEEK_CUR: + result = file->offset + offset; + break; + case SEEK_END: { + // If we're in append mode we already reset to the end, but if we're not + // in append mode then do the reset to the end here. + if (!(file->oflag & O_APPEND) && file_seek_end(file) < 0) + return -1; + result = file->offset + offset; + break; + } + default: + errno = EINVAL; + return -1; + } + if (result < 0) { + errno = EINVAL; + return -1; + } + file->offset = result; + file_close_streams(data); + return file->offset; +} + +static int file_set_blocking(void *data, bool blocking) { abort(); } + +static int file_fcntl_getfl(void *data) { abort(); } + +static int file_fcntl_setfl(void *data, int flags) { abort(); } + +static int file_read_stream(void *data, void *buf, size_t nbyte, + waitable_t *waitable, wasip3_waitable_status_t *out, + off_t **offs) { + file3_t *file = (file3_t *)data; + if (file->read.f0==0) { + filesystem_method_descriptor_read_via_stream( + filesystem_borrow_descriptor(file->file_handle), file->offset, &file->read); + } + *waitable = file->read.f0; + *out = filesystem_stream_u8_read(file->read.f0, buf, nbyte); + *offs = &file->offset; + return 0; +} + +static descriptor_vtable_t file_vtable = { + .free = file_free, + .get_file = file_get_file, + .set_blocking = file_set_blocking, + .fstat = file_fstat, + .seek = file_seek, + .close_streams = file_close_streams, + .fcntl_getfl = file_fcntl_getfl, + .fcntl_setfl = file_fcntl_setfl, + .read3 = file_read_stream, +}; int __wasilibc_add_file(filesystem_own_descriptor_t file_handle, int oflag) { - // TODO(wasip3) - errno = EOPNOTSUPP; - return -1; + file3_t *file = calloc(1, sizeof(file3_t)); + if (!file) { + filesystem_descriptor_drop_own(file_handle); + errno = ENOMEM; + return -1; + } + assert(file_handle.__handle != 0); + file->file_handle = file_handle; + file->oflag = oflag; + + // if (oflag == O_WRONLY) { + // filesystem_stream_u8_t write_read = filesystem_stream_u8_new(&file->write); + // file->write_task = filesystem_method_descriptor_write_via_stream( + // filesystem_borrow_descriptor(file_handle), write_read, 0, + // &file->write_error); + // } + + descriptor_table_entry_t entry; + entry.vtable = &file_vtable; + entry.data = file; + return descriptor_table_insert(entry); } #endif // __wasip3__ diff --git a/libc-bottom-half/sources/wasip3_file_utils.c b/libc-bottom-half/sources/wasip3_file_utils.c new file mode 100644 index 000000000..0d87dc827 --- /dev/null +++ b/libc-bottom-half/sources/wasip3_file_utils.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include + +#ifdef __wasip3__ +/** + * Validates that `ptr_signed` is a valid utf-8 string. + * + * Returns the byte-length of the string on success, or -1 if it's invalid + * utf-8. + */ +static int validate_utf8(const char *ptr_signed) { + const unsigned char *ptr = (const unsigned char *)ptr_signed; + size_t i = 0; + while (1) { + unsigned char c = ptr[i]; + size_t codepoint_size; + + if (c == 0x00) { + break; + } else if (c <= 0x7F) { + // fast path for ascii-like characters, just turn the loop. + i++; + continue; + } else if ((c & 0xE0) == 0xC0) { + codepoint_size = 2; + // Disallow overlong encodings, which in this case is either 0xc0 or + // 0xc1. All other patterns represent a valid encoding. + if (c <= 0xC1) + return -1; + } else if ((c & 0xF0) == 0xE0) { + codepoint_size = 3; + // Disallow overlong encodings by ensuring that if no bits are set in + // this byte then the highest payload bit in the next byte must be set. + if (c == 0xE0 && (ptr[i + 1] & 0x20) == 0x00) + return -1; + + // Disallow surrogates which start with 0xED and are followed with + // something bigger than 0xA0. + if (c == 0xED && ptr[i + 1] >= 0xA0) + return -1; + } else if ((c & 0xF8) == 0xF0) { + codepoint_size = 4; + + // Disallow overlong encodings by ensuring that if no payload bits are + // set in this byte then one of the upper two payload bits in the next + // byte are set. + if (c == 0xF0 && (ptr[i + 1] & 0x30) == 0x00) + return -1; + + // Disallow codepoints beyond U+10FFFF which start with 0xF4 and are + // followed with something bigger than 0x8F, or if the leading byte is + // larger than 0xF4. + if (c == 0xF4 && ptr[i + 1] >= 0x90) + return -1; + if (c > 0xF4) + return -1; + } else { + return -1; + } + + // Validate all continuation bytes are `0b10......` + for (size_t j = 1; j < codepoint_size; j++) + if ((ptr[i + j] & 0xC0) != 0x80) + return -1; + i += codepoint_size; + } + return i; +} + +int wasip3_string_from_c(const char *s, wasip3_string_t *out) { + int len = validate_utf8(s); + if (len < 0) { + errno = EILSEQ; + return -1; + } + out->ptr = (uint8_t *)s; + out->len = len; + return 0; +} + +ssize_t __wasilibc_write3(int fildes, void const *buf, size_t nbyte) { + descriptor_table_entry_t *entry = descriptor_table_get_ref(fildes); + if (!entry) + return -1; + if (!entry->vtable->write3) { + errno = EOPNOTSUPP; + return -1; + } + off_t *off; + waitable_t output_stream; + wasip3_waitable_status_t status; + if ((*entry->vtable->write3)(entry->data, 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(); + } +} + +ssize_t __wasilibc_read3(int fildes, void *buf, size_t nbyte) { + descriptor_table_entry_t *entry = descriptor_table_get_ref(fildes); + if (!entry) + return -1; + if (!entry->vtable->read3) { + errno = EOPNOTSUPP; + return -1; + } + off_t *off; + waitable_t waitable; + wasip3_waitable_status_t status; + if ((*entry->vtable->read3)(entry->data, 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(); + } +} +#endif // __wasip3__ diff --git a/libc-bottom-half/sources/wasip3_stdio.c b/libc-bottom-half/sources/wasip3_stdio.c index 5de4aa9f6..51b60babc 100644 --- a/libc-bottom-half/sources/wasip3_stdio.c +++ b/libc-bottom-half/sources/wasip3_stdio.c @@ -2,10 +2,155 @@ #include #ifdef __wasip3__ +#include +#include +#include +#include +#include + +typedef struct { + stdin_stream_u8_t input; + stdin_future_result_void_error_code_t future; + terminal_input_own_terminal_input_t terminal_in; + + stdin_stream_u8_writer_t stdout; + // contents will be filled by host (once stdout has an error) + stdout_result_void_error_code_t stdout_result; + wasip3_subtask_t stdout_task; + terminal_output_own_terminal_output_t terminal_out; +} stdio3_t; + +static void stdio3_free(void *data) { + stdio3_t *stdio = (stdio3_t *)data; + if (stdio->terminal_in.__handle) + terminal_input_terminal_input_drop_own(stdio->terminal_in); + if (stdio->future) + stdin_future_result_void_error_code_drop_readable(stdio->future); + if (stdio->input) + stdin_stream_u8_drop_readable(stdio->input); + + if (stdio->terminal_out.__handle) + terminal_output_terminal_output_drop_own(stdio->terminal_out); + if (stdio->stdout_task) + wasip3_subtask_cancel(stdio->stdout_task); + if (stdio->stdout) + stdin_stream_u8_drop_writable(stdio->stdout); + free(stdio); +} + +static int stdio3_write(void *data, void const *buf, size_t nbyte, + waitable_t *waitable, wasip3_waitable_status_t *out, + off_t **offs) { + stdio3_t *stdio = (stdio3_t *)data; + if (!stdio->stdout) { + errno = EBADF; + return -1; + } + *waitable = stdio->stdout; + *out = stdin_stream_u8_write(stdio->stdout, buf, nbyte); + *offs = NULL; + return 0; +} + +static int stdio3_read(void *data, void *buf, size_t nbyte, + waitable_t *waitable, wasip3_waitable_status_t *out, + off_t **offs) { + stdio3_t *stdio = (stdio3_t *)data; + if (!stdio->input) { + errno = EBADF; + return -1; + } + *waitable = stdio->input; + *out = stdin_stream_u8_read(stdio->input, buf, nbyte); + *offs = NULL; + return 0; +} + +static int stdio3_fstat(void *data, struct stat *buf) { + memset(buf, 0, sizeof(*buf)); + return 0; +} + +static int stdio3_fcntl_getfl(void *data) { + stdio3_t *stdio = (stdio3_t *)data; + if (stdio->stdout == 0) { + return O_RDONLY; + } else { + return O_WRONLY; + } +} + +static int stdio3_isatty(void *data) { + stdio3_t *stdio = (stdio3_t *)data; + return stdio->terminal_in.__handle != 0 || stdio->terminal_out.__handle != 0; +} + +static descriptor_vtable_t stdio3_vtable = { + .free = stdio3_free, + .read3 = stdio3_read, + .write3 = stdio3_write, + .fstat = stdio3_fstat, + .fcntl_getfl = stdio3_fcntl_getfl, + .isatty = stdio3_isatty, +}; + +static int stdio_add_input() { + stdio3_t *stdio = calloc(1, sizeof(stdio3_t)); + if (!stdio) { + errno = ENOMEM; + return -1; + } + stdin_tuple2_stream_u8_future_result_void_error_code_t stdin; + stdin_read_via_stream(&stdin); + + if (!terminal_stdin_get_terminal_stdin(&stdio->terminal_in)) + stdio->terminal_in.__handle = 0; + + stdio->input = stdin.f0; + stdio->future = stdin.f1; + + descriptor_table_entry_t entry; + entry.vtable = &stdio3_vtable; + entry.data = stdio; + return descriptor_table_insert(entry); +} + +static int stdio3_add_output( + // int fd, + wasip3_subtask_status_t (*func)(stdin_stream_u8_t data, + stdout_result_void_error_code_t *result), + bool (*terminal)(terminal_stdout_own_terminal_output_t *ret)) { + stdio3_t *stdio = calloc(1, sizeof(stdio3_t)); + if (!stdio) { + errno = ENOMEM; + return -1; + } + stdin_stream_u8_t read_side = stdin_stream_u8_new(&stdio->stdout); + wasip3_subtask_status_t res = (*func)(read_side, &stdio->stdout_result); + stdio->stdout_task = WASIP3_SUBTASK_HANDLE(res); + + if (!(*terminal)(&stdio->terminal_out)) + stdio->terminal_out.__handle = 0; + + descriptor_table_entry_t entry; + entry.vtable = &stdio3_vtable; + entry.data = stdio; + return descriptor_table_insert(entry); +} int __wasilibc_init_stdio() { - // TODO(wasip3) - errno = EOPNOTSUPP; - return -1; + if (stdio_add_input() < 0) + return -1; + if (stdio3_add_output(stdout_write_via_stream, + terminal_stdout_get_terminal_stdout) < 0) + return -1; + // assuming that stdout and stderr functions are compatible + if (stdio3_add_output( + (wasip3_subtask_status_t (*)( + stdin_stream_u8_t, + stdout_result_void_error_code_t *))stderr_write_via_stream, + terminal_stderr_get_terminal_stderr) < 0) + return -1; + return 0; } #endif // __wasip3__ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 38c599658..ca568ba30 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -242,7 +242,7 @@ add_wasilibc_test(append.c FS FAILP3) add_wasilibc_test(argv_two_args.c ARGV foo bar) add_wasilibc_test(clock_nanosleep.c) add_wasilibc_test(chdir.c FS FAILP3) -add_wasilibc_test(close.c FS FAILP3) +add_wasilibc_test(close.c FS) add_wasilibc_test(external_env.c ENV VAR1=foo VAR2=bar) add_wasilibc_test(fadvise.c FS FAILP3) add_wasilibc_test(fallocate.c FS FAILP3) @@ -259,14 +259,14 @@ add_wasilibc_test(ftruncate.c FS FAILP3) add_wasilibc_test(fts.c FS FAILP3) add_wasilibc_test(fwscanf.c FS FAILP3) add_wasilibc_test(getentropy.c) -add_wasilibc_test(hello.c PASS_REGULAR_EXPRESSION "Hello, World!" FAILP3) +add_wasilibc_test(hello.c PASS_REGULAR_EXPRESSION "Hello, World!") add_wasilibc_test(ioctl.c FS FAILP3) add_wasilibc_test(isatty.c FS FAILP3) add_wasilibc_test(link.c FS FAILP3) add_wasilibc_test(lseek.c FS FAILP3) add_wasilibc_test(memchr.c LDFLAGS -Wl,--stack-first -Wl,--initial-memory=327680) add_wasilibc_test(memcmp.c LDFLAGS -Wl,--stack-first -Wl,--initial-memory=327680) -add_wasilibc_test(opendir.c FS FAILP3 ARGV /) +add_wasilibc_test(opendir.c FS ARGV /) add_wasilibc_test(open_relative_path.c FS FAILP3 ARGV /) add_wasilibc_test(poll.c FS FAILP3) add_wasilibc_test(preadvwritev.c FS FAILP3) @@ -277,7 +277,7 @@ add_wasilibc_test(rename.c FS FAILP3) add_wasilibc_test(rmdir.c FS FAILP3) add_wasilibc_test(scandir.c FS FAILP3) add_wasilibc_test(stat.c FS FAILP3) -add_wasilibc_test(stdio.c FS FAILP3) +add_wasilibc_test(stdio.c FS) add_wasilibc_test(strchrnul.c LDFLAGS -Wl,--stack-first -Wl,--initial-memory=327680) add_wasilibc_test(strlen.c LDFLAGS -Wl,--stack-first -Wl,--initial-memory=327680) add_wasilibc_test(strptime.c)