diff --git a/expected/wasm32-wasip3/defined-symbols.txt b/expected/wasm32-wasip3/defined-symbols.txt index 61ac1ad71..b6fe4c7e2 100644 --- a/expected/wasm32-wasip3/defined-symbols.txt +++ b/expected/wasm32-wasip3/defined-symbols.txt @@ -1005,6 +1005,7 @@ optopt optreset pathconf perror +pipe poll posix_close posix_fadvise diff --git a/libc-bottom-half/CMakeLists.txt b/libc-bottom-half/CMakeLists.txt index c7c8013fe..819aefa03 100644 --- a/libc-bottom-half/CMakeLists.txt +++ b/libc-bottom-half/CMakeLists.txt @@ -166,6 +166,7 @@ if (WASI STREQUAL "p3") sources/wasip3_block_on.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 diff --git a/libc-bottom-half/sources/wasip3_pipe.c b/libc-bottom-half/sources/wasip3_pipe.c new file mode 100644 index 000000000..33277cc18 --- /dev/null +++ b/libc-bottom-half/sources/wasip3_pipe.c @@ -0,0 +1,102 @@ +#include + +#ifdef __wasip3__ +#include +#include +#include +#include + +typedef struct { + wasip3_write_t output; +} pipe3w_t; + +typedef struct { + filesystem_tuple2_stream_u8_future_result_void_error_code_t input; +} pipe3r_t; + +static int pipe_read_stream( + void *data, + filesystem_tuple2_stream_u8_future_result_void_error_code_t **out, + off_t **offs) { + pipe3r_t *file = (pipe3r_t *)data; + *out = &file->input; + *offs = 0; + return 0; +} + +static void pipe_r_free(void *data) { + pipe3r_t *file = (pipe3r_t *)data; + filesystem_stream_u8_drop_readable(file->input.f0); + free(file); +} + +static int pipe_write_stream(void *data, wasip3_write_t **out, off_t **offs) { + pipe3w_t *file = (pipe3w_t *)data; + *out = &file->output; + *offs = 0; + return 0; +} + +static void pipe_w_free(void *data) { + pipe3w_t *file = (pipe3w_t *)data; + filesystem_stream_u8_drop_writable(file->output.output); + free(file); +} + +static descriptor_vtable_t pipe_r_vtable = { + .free = pipe_r_free, + .get_read_stream3 = pipe_read_stream, +}; + +static descriptor_vtable_t pipe_w_vtable = { + .free = pipe_w_free, + .get_write_stream3 = pipe_write_stream, +}; + +int pipe(int pipefd[2]) { + pipe3w_t *writehandle = calloc(1, sizeof(pipe3w_t)); + if (!writehandle) { + errno = ENOMEM; + return -1; + } + pipe3r_t *readhandle = calloc(1, sizeof(pipe3r_t)); + if (!readhandle) { + free(writehandle); + errno = ENOMEM; + return -1; + } + readhandle->input.f0 = filesystem_stream_u8_new(&writehandle->output.output); + descriptor_table_entry_t entry; + entry.vtable = &pipe_r_vtable; + entry.data = readhandle; + int pipefd0 = descriptor_table_insert(entry); + if (pipefd0 < 0) { + pipe_r_free(readhandle); + pipe_w_free(writehandle); + return -1; + } + entry.vtable = &pipe_w_vtable; + entry.data = writehandle; + int pipefd1 = descriptor_table_insert(entry); + if (pipefd1 < 0) { + pipe_r_free(readhandle); + pipe_w_free(writehandle); + descriptor_table_remove(pipefd0); + return -1; + } + // signal non-eof condition + writehandle->output.subtask = WASIP3_SUBTASK_STARTING; + pipefd[0] = pipefd0; + pipefd[1] = pipefd1; + return 0; +} + +int pipe2(int pipefd[2], int flags) { + if (flags != 0) { + errno = EOPNOTSUPP; + return -1; + } + return pipe(pipefd); +} + +#endif diff --git a/libc-top-half/musl/include/unistd.h b/libc-top-half/musl/include/unistd.h index c3158e6e6..632ff44e5 100644 --- a/libc-top-half/musl/include/unistd.h +++ b/libc-top-half/musl/include/unistd.h @@ -19,6 +19,7 @@ extern "C" { #define SEEK_HOLE 4 #else #include <__header_unistd.h> +#include // for pipe availability #endif #ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */ @@ -45,7 +46,7 @@ extern "C" { #include -#ifdef __wasilibc_unmodified_upstream /* WASI has no pipe */ +#if defined(__wasilibc_unmodified_upstream) || defined(__wasip3__) /* WASI<0.3 has no pipe */ int pipe(int [2]); int pipe2(int [2], int); #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1b1122cab..14c1c0292 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -271,6 +271,7 @@ 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(open_relative_path.c FS FAILP3 ARGV /) +add_wasilibc_test(pipe.c) add_wasilibc_test(poll.c FS FAILP3) add_wasilibc_test(preadvwritev.c FS FAILP3) add_wasilibc_test(preadwrite.c FS FAILP3) diff --git a/test/src/pipe.c b/test/src/pipe.c new file mode 100644 index 000000000..4e6618a11 --- /dev/null +++ b/test/src/pipe.c @@ -0,0 +1,28 @@ +#include "test.h" +#include +#include +#include + +#define PATTERNSIZE 16 +static const char PATTERN[PATTERNSIZE] = { + 'A', 'B', 'C', 'D', '0', '1', '2', '3', 'a', 'b', 'c', 'd', 0, 1, 2, 3}; + +#define TEST(c, ...) ((c) ? 1 : (t_error(#c " failed: " __VA_ARGS__), 0)) + +int main(void) { +#ifdef __wasip3__ // pipe only works on wasip3 or up + int pipefd[2]; + char buf[PATTERNSIZE]; + int res; + + TEST(pipe(pipefd) >= 0); + + TEST(write(pipefd[1], PATTERN, PATTERNSIZE) == PATTERNSIZE); + + TEST(read(pipefd[0], buf, PATTERNSIZE) == PATTERNSIZE); + + TEST(close(pipefd[0]) >= 0); + TEST(close(pipefd[1]) >= 0); +#endif + return 0; +}