Skip to content

Commit 3f7371f

Browse files
authored
Merge wasip2/wasip3 reading/writing (WebAssembly#756)
* Generalize the `wasip2_{read,write}_t` types to `wasi_{read,write}_t` with conditional internals depending on the WASI version. * Fix error handling for stdin to use stdin error codes instead of filesystem error codes. * Call `subtask.drop` for writes to acknowledge the subtask being done. * When stdin is done, drop the future for the error after it's read to ensure the future isn't read twice.
1 parent c2989f3 commit 3f7371f

13 files changed

Lines changed: 158 additions & 177 deletions

File tree

expected/wasm32-wasip3/defined-symbols.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ __wasilibc_parse_port
331331
__wasilibc_populate_preopens
332332
__wasilibc_pthread_self
333333
__wasilibc_random
334-
__wasilibc_read_stream3
334+
__wasilibc_read
335335
__wasilibc_rename_newat
336336
__wasilibc_rename_oldat
337337
__wasilibc_reset_preopens
@@ -345,7 +345,7 @@ __wasilibc_unspecified_addr
345345
__wasilibc_utimens
346346
__wasilibc_wasi_family_to_libc
347347
__wasilibc_wasi_to_sockaddr
348-
__wasilibc_write_stream3
348+
__wasilibc_write
349349
__wasm_call_dtors
350350
__wcscoll_l
351351
__wcsftime_l

libc-bottom-half/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ else()
139139
sources/descriptor_table.c
140140
sources/getsockpeername.c
141141
sources/listen.c
142+
sources/file_utils.c
142143
sources/recv.c
143144
sources/send.c
144145
sources/shutdown.c
@@ -155,7 +156,6 @@ if(WASI STREQUAL "p2")
155156
sources/netdb.c
156157
sources/wasip2.c
157158
sources/wasip2_file.c
158-
sources/wasip2_file_utils.c
159159
sources/wasip2_stdio.c
160160
)
161161
endif()
@@ -165,7 +165,6 @@ if (WASI STREQUAL "p3")
165165
sources/wasip3.c
166166
sources/wasip3_block_on.c
167167
sources/wasip3_file.c
168-
sources/wasip3_file_utils.c
169168
sources/wasip3_stdio.c
170169
)
171170
endif()

libc-bottom-half/cloudlibc/src/libc/poll/poll.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ static int poll_impl(struct pollfd *fds, size_t nfds, int timeout) {
216216

217217
if (pollfd->events & POLLRDNORM) {
218218
if (entry->vtable->get_read_stream) {
219-
wasip2_read_t read;
219+
wasi_read_t read;
220220
if (entry->vtable->get_read_stream(entry->data, &read) < 0)
221221
return -1;
222222
if (__wasilibc_poll_add_input_stream(&state, read.input, read.pollable) < 0)
@@ -229,7 +229,7 @@ static int poll_impl(struct pollfd *fds, size_t nfds, int timeout) {
229229

230230
if (pollfd->events & POLLWRNORM) {
231231
if (entry->vtable->get_write_stream) {
232-
wasip2_write_t write;
232+
wasi_write_t write;
233233
if (entry->vtable->get_write_stream(entry->data, &write) < 0)
234234
return -1;
235235
if (__wasilibc_poll_add_output_stream(&state, write.output, write.pollable) < 0)

libc-bottom-half/cloudlibc/src/libc/unistd/read.c

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ ssize_t read(int fildes, void *buf, size_t nbyte) {
2727
return -1;
2828
}
2929
return bytes_read;
30-
#elif defined(__wasip2__)
30+
#else
3131
descriptor_table_entry_t *entry = descriptor_table_get_ref(fildes);
3232
if (!entry)
3333
return -1;
3434
if (entry->vtable->get_read_stream) {
35-
wasip2_read_t read;
35+
wasi_read_t read;
3636
if (entry->vtable->get_read_stream(entry->data, &read) < 0)
3737
return -1;
3838
return __wasilibc_read(&read, buf, nbyte);
@@ -41,30 +41,5 @@ ssize_t read(int fildes, void *buf, size_t nbyte) {
4141
return entry->vtable->recvfrom(entry->data, buf, nbyte, 0, NULL, NULL);
4242
errno = EOPNOTSUPP;
4343
return -1;
44-
#elif defined(__wasip3__)
45-
filesystem_tuple2_stream_u8_future_result_void_error_code_t *stream;
46-
off_t *off;
47-
if (__wasilibc_read_stream3(fildes, &stream, &off)<0)
48-
return -1;
49-
wasip3_waitable_status_t status =
50-
filesystem_stream_u8_read(stream->f0, buf, nbyte);
51-
size_t amount = wasip3_waitable_block_on(status, stream->f0);
52-
if (amount > 0 || nbyte == 0) {
53-
if (off)
54-
*off += amount;
55-
return amount;
56-
} else {
57-
filesystem_result_void_error_code_t error;
58-
status = filesystem_future_result_void_error_code_read(stream->f1, &error);
59-
amount = wasip3_waitable_block_on(status, stream->f1);
60-
if (amount > 0 && error.is_err) {
61-
translate_error(error.val.err);
62-
return -1;
63-
}
64-
// EOF
65-
return 0;
66-
}
67-
#else
68-
# error "Unsupported WASI version"
6944
#endif
7045
}

libc-bottom-half/cloudlibc/src/libc/unistd/write.c

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ ssize_t write(int fildes, const void *buf, size_t nbyte) {
2828
return -1;
2929
}
3030
return bytes_written;
31-
#elif defined(__wasip2__)
31+
#else
3232
descriptor_table_entry_t *entry = descriptor_table_get_ref(fildes);
3333
if (!entry)
3434
return -1;
3535
if (entry->vtable->get_write_stream) {
36-
wasip2_write_t write;
36+
wasi_write_t write;
3737
if (entry->vtable->get_write_stream(entry->data, &write) < 0)
3838
return -1;
3939
return __wasilibc_write(&write, buf, nbyte);
@@ -42,33 +42,5 @@ ssize_t write(int fildes, const void *buf, size_t nbyte) {
4242
return entry->vtable->sendto(entry->data, buf, nbyte, 0, NULL, 0);
4343
errno = EOPNOTSUPP;
4444
return -1;
45-
#elif defined(__wasip3__)
46-
wasip3_write_t *write_end;
47-
off_t *off;
48-
if (__wasilibc_write_stream3(fildes, &write_end, &off) < 0)
49-
return -1;
50-
if (WASIP3_SUBTASK_STATE(write_end->subtask) == WASIP3_SUBTASK_STARTING ||
51-
WASIP3_SUBTASK_STATE(write_end->subtask) == WASIP3_SUBTASK_STARTED) {
52-
// the stream is still active
53-
wasip3_waitable_status_t status =
54-
filesystem_stream_u8_write(write_end->output, buf, nbyte);
55-
size_t amount = wasip3_waitable_block_on(status, write_end->output);
56-
if (amount > 0 || nbyte == 0) {
57-
if (off)
58-
*off += amount;
59-
return amount;
60-
}
61-
// error or eof
62-
wasip3_subtask_block_on(write_end->subtask);
63-
write_end->subtask = WASIP3_SUBTASK_RETURNED;
64-
}
65-
if (write_end->pending_result.is_err) {
66-
translate_error(write_end->pending_result.val.err);
67-
return -1;
68-
}
69-
// EOF
70-
return 0;
71-
#else
72-
# error "Unknown WASI version"
7345
#endif
7446
}

libc-bottom-half/headers/private/wasi/descriptor_table.h

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,54 @@
88
#include <sys/stat.h>
99
#include <netinet/in.h>
1010

11-
#ifdef __wasip2__
1211
// Metadata for WASI reads which is used to delegate to `__wasilibc_read(...)`
1312
// to perform the actual read of a stream.
14-
typedef struct wasip2_read_t {
15-
// The `wasi:io/streams.input-stream` that this is reading from.
16-
streams_borrow_input_stream_t input;
13+
typedef struct wasi_read_t {
1714
// An optional pointer to the internal offset of this stream, updated on
1815
// successful reads.
1916
off_t *offset;
20-
// A required pointer to an owned pollable for `input`. This is lazily
21-
// initialized as-necessary.
22-
poll_own_pollable_t *pollable;
2317
// Whether or not this read will use blocking I/O.
2418
bool blocking;
2519
// The timeout, in nanoseconds, for this operation.
2620
monotonic_clock_duration_t timeout;
27-
} wasip2_read_t;
21+
#ifdef __wasip2__
22+
// The `wasi:io/streams.input-stream` that this is reading from.
23+
streams_borrow_input_stream_t input;
24+
// A required pointer to an owned pollable for `input`. This is lazily
25+
// initialized as-necessary.
26+
poll_own_pollable_t *pollable;
27+
#else
28+
// The `stream<u8>` that's being read.
29+
filesystem_stream_u8_t stream;
30+
31+
// A callback/ptr pair to invoke when EOF is reached to set errno and return
32+
// an error code.
33+
int (*eof)(void*);
34+
void *eof_data;
35+
#endif
36+
} wasi_read_t;
2837

29-
// Same as `wasip2_read_t`, but for writes.
30-
typedef struct wasip2_write_t {
31-
streams_borrow_output_stream_t output;
38+
// Same as `wasip_read_t`, but for writes.
39+
typedef struct wasi_write_t {
3240
off_t *offset;
33-
poll_own_pollable_t *pollable;
3441
bool blocking;
3542
monotonic_clock_duration_t timeout;
36-
} wasip2_write_t;
37-
#endif
38-
39-
#ifdef __wasip3__
40-
// create an alias to distinguish the handle type in the API
41-
typedef uint32_t waitable_t;
4243

43-
/**
44-
* This data structure represents the write end of a file
45-
*/
46-
typedef struct wasip3_write_t {
44+
#ifdef __wasip2__
45+
streams_borrow_output_stream_t output;
46+
poll_own_pollable_t *pollable;
47+
#else
4748
filesystem_stream_u8_writer_t output;
4849
// contents will be filled by host (once write has an error)
4950
filesystem_result_void_error_code_t pending_result;
5051
// this task gets ready on error or eof
51-
wasip3_subtask_t subtask;
52-
} wasip3_write_t;
52+
wasip3_subtask_t *subtask;
53+
#endif
54+
} wasi_write_t;
55+
56+
#ifdef __wasip3__
57+
// create an alias to distinguish the handle type in the API
58+
typedef uint32_t waitable_t;
5359
#endif
5460

5561
/**
@@ -71,18 +77,12 @@ typedef struct descriptor_vtable_t {
7177
// =====================================================================
7278
// Generic I/O
7379

74-
#ifdef __wasip2__
7580
/// Looks up metadata to perform a read operation for this stream. This is used
7681
/// to implement the `read` syscall, for example, and is also used with `poll`
7782
/// when waiting for readability.
78-
int (*get_read_stream)(void*, wasip2_read_t*);
83+
int (*get_read_stream)(void*, wasi_read_t*);
7984
/// Same as `get_read_stream`, but for output streams.
80-
int (*get_write_stream)(void*, wasip2_write_t*);
81-
#endif
82-
#ifdef __wasip3__
83-
int (*get_read_stream3)(void*, filesystem_tuple2_stream_u8_future_result_void_error_code_t **out, off_t** off);
84-
int (*get_write_stream3)(void*, wasip3_write_t **write_end, off_t**);
85-
#endif
85+
int (*get_write_stream)(void*, wasi_write_t*);
8686

8787
/// Sets the nonblocking flag for this object to the specified value.
8888
int (*set_blocking)(void*, bool);

libc-bottom-half/headers/private/wasi/file_utils.h

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
#define __wasi_file_utils_h
33

44
#include <wasi/version.h>
5-
65
#if defined(__wasip2__) || defined(__wasip3__)
6+
77
#include <assert.h>
88
#include <wasi/wasip2.h>
99
#include <wasi/descriptor_table.h>
1010
#include <dirent.h>
1111
#include <fcntl.h>
1212
#include <errno.h>
13-
#endif
1413

1514
#ifdef __wasip2__
1615
/// Handles a `wasi:io/streams.stream-error` for a `read`-style operation.
@@ -50,7 +49,6 @@ static inline int wasip2_handle_write_error(streams_stream_error_t error) {
5049
int wasip2_string_from_c(const char *s, wasip2_string_t* out);
5150
#endif
5251

53-
#if defined(__wasip2__) || defined(__wasip3__)
5452
// Succeed only if fd is bound to a file handle in the descriptor table
5553
static inline int fd_to_file_handle(int fd, filesystem_borrow_descriptor_t* result) {
5654
descriptor_table_entry_t* entry = descriptor_table_get_ref(fd);
@@ -62,25 +60,16 @@ static inline int fd_to_file_handle(int fd, filesystem_borrow_descriptor_t* resu
6260
}
6361
return entry->vtable->get_file(entry->data, result);
6462
}
65-
#endif
6663

67-
#ifdef __wasip2__
6864
// Reads from `read` into `buf`/`len`
6965
//
7066
// This perform the read configured by `read`, e.g. whether it's blocking or
7167
// not, and places the result in the specified buffer. Used to implement
7268
// `read` and `recvfrom`, for example.
73-
ssize_t __wasilibc_read(wasip2_read_t *read, void *buf, size_t len);
69+
ssize_t __wasilibc_read(wasi_read_t *read, void *buf, size_t len);
7470
// Same as `__wasilibc_read`, but for writes.
75-
ssize_t __wasilibc_write(wasip2_write_t *write, const void *buf, size_t len);
76-
#endif
77-
78-
#ifdef __wasip3__
79-
int __wasilibc_write_stream3(int fildes, wasip3_write_t **write_end, off_t **off);
80-
int __wasilibc_read_stream3(int fildes, filesystem_tuple2_stream_u8_future_result_void_error_code_t **stream, off_t **off);
81-
#endif
71+
ssize_t __wasilibc_write(wasi_write_t *write, const void *buf, size_t len);
8272

83-
#if defined(__wasip2__) || defined(__wasip3__)
8473
static inline unsigned dir_entry_type_to_d_type(filesystem_descriptor_type_t ty) {
8574
switch(ty) {
8675
case FILESYSTEM_DESCRIPTOR_TYPE_UNKNOWN:
@@ -104,6 +93,6 @@ static inline unsigned dir_entry_type_to_d_type(filesystem_descriptor_type_t ty)
10493
}
10594
}
10695

107-
#endif
96+
#endif // __wasip2__ || __wasip3__
10897

109-
#endif
98+
#endif // __wasi_file_utils_h

libc-bottom-half/sources/wasip2_file_utils.c renamed to libc-bottom-half/sources/file_utils.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
#include <stddef.h>
55
#include <string.h>
66
#include <wasi/file_utils.h>
7+
#include <wasi/wasip3_block.h>
78

89
#ifdef __wasip2__
9-
1010
/**
1111
* Validates that `ptr_signed` is a valid utf-8 string.
1212
*
@@ -82,9 +82,11 @@ int wasip2_string_from_c(const char *s, wasip2_string_t *out) {
8282
out->len = len;
8383
return 0;
8484
}
85+
#endif
8586

86-
ssize_t __wasilibc_write(wasip2_write_t *write, const void *buffer,
87+
ssize_t __wasilibc_write(wasi_write_t *write, const void *buffer,
8788
size_t length) {
89+
#if defined(__wasip2__)
8890
assert(write->output.__handle != 0);
8991
while (true) {
9092
streams_stream_error_t error;
@@ -158,9 +160,36 @@ ssize_t __wasilibc_write(wasip2_write_t *write, const void *buffer,
158160
poll_method_pollable_block(pollable_borrow);
159161
}
160162
}
163+
#elif defined(__wasip3__)
164+
if (WASIP3_SUBTASK_STATE(*write->subtask) == WASIP3_SUBTASK_STARTING ||
165+
WASIP3_SUBTASK_STATE(*write->subtask) == WASIP3_SUBTASK_STARTED) {
166+
// the stream is still active
167+
wasip3_waitable_status_t status =
168+
filesystem_stream_u8_write(write->output, buffer, length);
169+
size_t amount = wasip3_waitable_block_on(status, write->output);
170+
if (amount > 0 || length == 0) {
171+
if (write->offset)
172+
*write->offset += amount;
173+
return amount;
174+
}
175+
// error or eof
176+
wasip3_subtask_block_on(*write->subtask);
177+
wasip3_subtask_drop(*write->subtask);
178+
*write->subtask = WASIP3_SUBTASK_RETURNED;
179+
}
180+
if (write->pending_result.is_err) {
181+
translate_error(write->pending_result.val.err);
182+
return -1;
183+
}
184+
// EOF
185+
return 0;
186+
#else
187+
#error "Unknown WASI version"
188+
#endif
161189
}
162190

163-
ssize_t __wasilibc_read(wasip2_read_t *read, void *buffer, size_t length) {
191+
ssize_t __wasilibc_read(wasi_read_t *read, void *buffer, size_t length) {
192+
#if defined(__wasip2__)
164193
while (true) {
165194
wasip2_list_u8_t result;
166195
streams_stream_error_t error;
@@ -223,6 +252,17 @@ ssize_t __wasilibc_read(wasip2_read_t *read, void *buffer, size_t length) {
223252
poll_method_pollable_block(pollable_borrow);
224253
}
225254
}
255+
#elif defined(__wasip3__)
256+
wasip3_waitable_status_t status =
257+
filesystem_stream_u8_read(read->stream, buffer, length);
258+
size_t amount = wasip3_waitable_block_on(status, read->stream);
259+
if (amount > 0 || length == 0) {
260+
if (read->offset)
261+
*read->offset += amount;
262+
return amount;
263+
}
264+
return read->eof(read->eof_data);
265+
#else
266+
#error "Unknown WASI version"
267+
#endif
226268
}
227-
228-
#endif // __wasip2__

0 commit comments

Comments
 (0)