Skip to content

Commit a651bed

Browse files
cpetigalexcrichton
authored andcommitted
Wasip3: File handing implementation
This is an initial implementation of some basic file-handling functions such as reading, writing, opening directories, iterating them, etc. A number of previously failing tests are now passing and the `wasip2_file.c` implementation is now merged with WASIp3 with `file.c`. Bindings generation is also updated to flag some specific functions as being lowered synchronously as libc always blocks on the result.
1 parent 3179325 commit a651bed

37 files changed

+609
-258
lines changed

cmake/bindings.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ add_custom_target(
107107
--rename wasi:cli/terminal-stdin@${wasip3-version}=terminal_stdin
108108
--rename wasi:cli/terminal-stdout@${wasip3-version}=terminal_stdout
109109
--rename wasi:cli/terminal-stderr@${wasip3-version}=terminal_stderr
110+
111+
# Disable async bindings generation for some functions which are only
112+
# ever called synchronously within libc.
113+
"--async=-wasi:filesystem/types@${wasip3-version}#[method]descriptor.metadata-hash"
114+
"--async=-wasi:filesystem/types@${wasip3-version}#[method]descriptor.metadata-hash-at"
115+
"--async=-wasi:filesystem/types@${wasip3-version}#[method]descriptor.stat"
116+
"--async=-wasi:filesystem/types@${wasip3-version}#[method]descriptor.get-flags"
117+
"--async=-wasi:filesystem/types@${wasip3-version}#[method]descriptor.open-at"
118+
"--async=-wasi:filesystem/types@${wasip3-version}#[method]descriptor.read-directory"
119+
"--async=-wasi:clocks/monotonic-clock@${wasip3-version}#wait-until"
120+
"--async=-wasi:clocks/monotonic-clock@${wasip3-version}#wait-for"
110121
${CMAKE_SOURCE_DIR}/wasi/p3/wit
111122
COMMAND cmake -E copy wasip3.h ${bottom_half}/headers/public/wasi/__generated_wasip3.h
112123
COMMAND cmake -E copy wasip3_component_type.o ${bottom_half}/sources

expected/wasm32-wasip2/defined-symbols.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,7 @@ vwprintf
14941494
vwscanf
14951495
wall_clock_now
14961496
wall_clock_resolution
1497+
wasi_string_from_c
14971498
wasip2_list_string_free
14981499
wasip2_list_tuple2_string_string_free
14991500
wasip2_list_u32_free
@@ -1502,7 +1503,6 @@ wasip2_option_string_free
15021503
wasip2_string_dup
15031504
wasip2_string_dup_n
15041505
wasip2_string_free
1505-
wasip2_string_from_c
15061506
wasip2_string_set
15071507
wasip2_tuple2_string_string_free
15081508
wcpcpy

expected/wasm32-wasip3/defined-symbols.txt

Lines changed: 6 additions & 3 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
@@ -1463,21 +1463,25 @@ vswprintf
14631463
vswscanf
14641464
vwprintf
14651465
vwscanf
1466+
wasi_string_from_c
14661467
wasip3_backpressure_dec
14671468
wasip3_backpressure_inc
14681469
wasip3_context_get_0
14691470
wasip3_context_get_1
14701471
wasip3_context_set_0
14711472
wasip3_context_set_1
1473+
wasip3_future_block_on
14721474
wasip3_list_string_free
14731475
wasip3_list_tuple2_string_string_free
14741476
wasip3_list_u8_free
14751477
wasip3_option_string_free
1478+
wasip3_stream_block_on
14761479
wasip3_string_dup
14771480
wasip3_string_dup_n
14781481
wasip3_string_free
14791482
wasip3_string_set
14801483
wasip3_subtask_block_on
1484+
wasip3_subtask_block_on_and_drop
14811485
wasip3_subtask_cancel
14821486
wasip3_subtask_drop
14831487
wasip3_task_cancel
@@ -1495,7 +1499,6 @@ wasip3_thread_yield_cancellable
14951499
wasip3_thread_yield_to_suspended
14961500
wasip3_thread_yield_to_suspended_cancellable
14971501
wasip3_tuple2_string_string_free
1498-
wasip3_waitable_block_on
14991502
wasip3_waitable_join
15001503
wasip3_waitable_set_drop
15011504
wasip3_waitable_set_new

libc-bottom-half/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ else()
140140
sources/getsockpeername.c
141141
sources/listen.c
142142
sources/file_utils.c
143+
sources/file.c
143144
sources/recv.c
144145
sources/send.c
145146
sources/shutdown.c
@@ -155,7 +156,6 @@ if(WASI STREQUAL "p2")
155156
list(APPEND bottom_half_sources
156157
sources/netdb.c
157158
sources/wasip2.c
158-
sources/wasip2_file.c
159159
sources/wasip2_stdio.c
160160
)
161161
endif()
@@ -164,7 +164,6 @@ if (WASI STREQUAL "p3")
164164
list(APPEND bottom_half_sources
165165
sources/wasip3.c
166166
sources/wasip3_block_on.c
167-
sources/wasip3_file.c
168167
sources/wasip3_stdio.c
169168
)
170169
endif()

libc-bottom-half/cloudlibc/src/libc/dirent/dirent_impl.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct _DIR {
2828
size_t skip;
2929
size_t offset;
3030
#elif defined(__wasip3__)
31-
filesystem_stream_directory_entry_t stream;
31+
filesystem_tuple2_stream_directory_entry_future_result_void_error_code_t stream;
3232
size_t skip;
3333
size_t offset;
3434
#else
@@ -40,4 +40,26 @@ struct _DIR {
4040
size_t dirent_size;
4141
};
4242

43+
static void dirent_close_streams(DIR *dirp) {
44+
#if defined(__wasip1__)
45+
// nothing to close ...
46+
#elif defined(__wasip2__)
47+
if (dirp->stream.__handle) {
48+
filesystem_directory_entry_stream_drop_own(dirp->stream);
49+
dirp->stream.__handle = 0;
50+
}
51+
#elif defined(__wasip3__)
52+
if (dirp->stream.f0 != 0) {
53+
filesystem_stream_directory_entry_drop_readable(dirp->stream.f0);
54+
dirp->stream.f0 = 0;
55+
}
56+
if (dirp->stream.f1 != 0) {
57+
filesystem_future_result_void_error_code_drop_readable(dirp->stream.f1);
58+
dirp->stream.f1 = 0;
59+
}
60+
#else
61+
# error "Unknown WASI version"
62+
#endif
63+
}
64+
4365
#endif

libc-bottom-half/cloudlibc/src/libc/dirent/fdclosedir.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,8 @@ int fdclosedir(DIR *dirp) {
1111
int fd = dirp->fd;
1212
#if defined(__wasip1__)
1313
free(dirp->buffer);
14-
#elif defined(__wasip2__)
15-
if (dirp->stream.__handle != 0)
16-
filesystem_directory_entry_stream_drop_own(dirp->stream);
17-
#elif defined(__wasip3__)
18-
if (dirp->stream != 0)
19-
filesystem_stream_directory_entry_drop_readable(dirp->stream);
14+
#elif defined(__wasip2__) || defined(__wasip3__)
15+
dirent_close_streams(dirp);
2016
#else
2117
# error "Unsupported WASI version"
2218
#endif

libc-bottom-half/cloudlibc/src/libc/dirent/fdopendir.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ DIR *fdopendir(int fd) {
4949
dirp->dirent = NULL;
5050
dirp->dirent_size = 1;
5151
return dirp;
52-
#elif defined(__wasip2__)
52+
#elif defined(__wasip2__) || defined(__wasip3__)
5353
// Translate the file descriptor to an internal handle
5454
filesystem_borrow_descriptor_t file_handle;
5555
if (fd_to_file_handle(fd, &file_handle) < 0) {
@@ -58,6 +58,7 @@ DIR *fdopendir(int fd) {
5858
}
5959

6060
// Read the directory
61+
#ifdef __wasip2__
6162
filesystem_own_directory_entry_stream_t result;
6263
filesystem_error_code_t error_code;
6364
bool ok = filesystem_method_descriptor_read_directory(file_handle,
@@ -69,18 +70,16 @@ DIR *fdopendir(int fd) {
6970
return NULL;
7071
}
7172

72-
dirp->fd = fd;
7373
dirp->stream = result;
74+
#elif defined(__wasip3__)
75+
filesystem_method_descriptor_read_directory(file_handle, &dirp->stream);
76+
#endif
77+
dirp->fd = fd;
7478
dirp->skip = 0;
7579
dirp->offset = 0;
7680
dirp->dirent = NULL;
7781
dirp->dirent_size = 1;
7882
return dirp;
79-
#elif defined(__wasip3__)
80-
// TODO(wasip3)
81-
errno = ENOTSUP;
82-
free(dirp);
83-
return NULL;
8483
#else
8584
# error "Unsupported WASI version"
8685
#endif

libc-bottom-half/cloudlibc/src/libc/dirent/readdir.c

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ static_assert(DT_REG == __WASI_FILETYPE_REGULAR_FILE, "Value mismatch");
3131
static_assert(DT_UNKNOWN == __WASI_FILETYPE_UNKNOWN, "Value mismatch");
3232
#endif
3333

34+
#ifdef __wasip3__
35+
#include <wasi/wasip3_block.h>
36+
#endif
37+
3438
// Grows a buffer to be large enough to hold a certain amount of data.
3539
#define GROW(buffer, buffer_size, target_size) \
3640
do { \
@@ -140,12 +144,13 @@ struct dirent *readdir(DIR *dirp) {
140144
}
141145
}
142146

143-
#elif defined(__wasip2__)
147+
#elif defined(__wasip2__) || defined(__wasip3__)
144148

145149
static int ensure_has_directory_stream(DIR *dirp, filesystem_borrow_descriptor_t *handle) {
146150
if (fd_to_file_handle(dirp->fd, handle) < 0)
147151
return -1;
148152

153+
#ifdef __wasip2__
149154
if (dirp->stream.__handle != 0)
150155
return 0;
151156

@@ -157,10 +162,15 @@ static int ensure_has_directory_stream(DIR *dirp, filesystem_borrow_descriptor_t
157162
translate_error(error_code);
158163
return -1;
159164
}
165+
#elif defined(__wasip3__)
166+
if (dirp->stream.f0 == 0)
167+
filesystem_method_descriptor_read_directory(*handle, &dirp->stream);
168+
#endif
160169
return 0;
161170
}
162171

163172
static struct dirent *readdir_next(DIR *dirp) {
173+
bool ok;
164174
filesystem_metadata_hash_value_t metadata;
165175
filesystem_error_code_t error_code;
166176
filesystem_borrow_descriptor_t dir_handle;
@@ -173,7 +183,7 @@ static struct dirent *readdir_next(DIR *dirp) {
173183
if (dirp->offset == 0) {
174184
dirp->offset += 1;
175185
GROW(dirp->dirent, dirp->dirent_size, offsetof(struct dirent, d_name) + 2);
176-
bool ok = filesystem_method_descriptor_metadata_hash(dir_handle,
186+
ok = filesystem_method_descriptor_metadata_hash(dir_handle,
177187
&metadata,
178188
&error_code);
179189
if (!ok) {
@@ -200,11 +210,12 @@ static struct dirent *readdir_next(DIR *dirp) {
200210
return dirp->dirent;
201211
}
202212

213+
#if defined(__wasip2__)
203214
filesystem_borrow_directory_entry_stream_t stream = filesystem_borrow_directory_entry_stream(dirp->stream);
204215
filesystem_option_directory_entry_t dir_entry_optional;
205-
bool ok = filesystem_method_directory_entry_stream_read_directory_entry(stream,
206-
&dir_entry_optional,
207-
&error_code);
216+
ok = filesystem_method_directory_entry_stream_read_directory_entry(stream,
217+
&dir_entry_optional,
218+
&error_code);
208219
if (!ok) {
209220
translate_error(error_code);
210221
return NULL;
@@ -216,6 +227,46 @@ static struct dirent *readdir_next(DIR *dirp) {
216227

217228
filesystem_directory_entry_t dir_entry = dir_entry_optional.val;
218229

230+
#elif defined(__wasip3__)
231+
filesystem_directory_entry_t dir_entry;
232+
233+
// Loop until at least one stream entry is read, or until the stream is closed.
234+
bool closed = false;
235+
while (1) {
236+
size_t amount =
237+
wasip3_stream_block_on(
238+
filesystem_stream_directory_entry_read(dirp->stream.f0, &dir_entry, 1),
239+
dirp->stream.f0,
240+
&closed);
241+
242+
// If something was read, then break out and process that below.
243+
if (amount > 0)
244+
break;
245+
246+
// If nothing was read and the stream isn't finished yet, try again.
247+
if (!closed)
248+
continue;
249+
250+
// If the stream's result future hasn't been read yet, do so here.
251+
if (dirp->stream.f1) {
252+
filesystem_result_void_error_code_t result;
253+
wasip3_future_block_on(
254+
filesystem_future_result_void_error_code_read(dirp->stream.f1, &result),
255+
dirp->stream.f1);
256+
filesystem_future_result_void_error_code_drop_readable(dirp->stream.f1);
257+
dirp->stream.f1 = 0;
258+
if (result.is_err)
259+
translate_error(result.val.err);
260+
}
261+
262+
// The stream is closed, so return NULL. This'll set `errno` based on the
263+
// result of the future above.
264+
return NULL;
265+
}
266+
#else
267+
#error "Unknown WASI version"
268+
#endif
269+
219270
// Ensure that the dirent is large enough to fit the filename
220271
size_t the_size = offsetof(struct dirent, d_name);
221272
GROW(dirp->dirent, dirp->dirent_size, the_size + dir_entry.name.len + 1);
@@ -232,7 +283,11 @@ static struct dirent *readdir_next(DIR *dirp) {
232283
&dir_entry.name,
233284
&metadata,
234285
&error_code);
286+
#ifdef __wasip2__
235287
wasip2_string_free(&dir_entry.name);
288+
#else
289+
wasip3_string_free(&dir_entry.name);
290+
#endif
236291
if (!ok) {
237292
translate_error(error_code);
238293
return NULL;
@@ -251,13 +306,6 @@ struct dirent *readdir(DIR *dirp) {
251306
}
252307
return result;
253308
}
254-
#elif defined(__wasip3__)
255-
struct dirent *readdir(DIR *dirp) {
256-
// TODO(wasip3)
257-
errno = ENOTSUP;
258-
free(dirp);
259-
return NULL;
260-
}
261309
#else
262310
# error "Unknown WASI version"
263311
#endif

libc-bottom-half/cloudlibc/src/libc/dirent/rewinddir.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@ void rewinddir(DIR *dirp) {
1313
dirp->cookie = __WASI_DIRCOOKIE_START;
1414
// Mark entire buffer as processed to force a read of new data.
1515
dirp->buffer_used = dirp->buffer_processed = dirp->buffer_size;
16-
#elif defined(__wasip2__)
17-
dirp->stream.__handle = 0;
18-
dirp->skip = 0;
19-
dirp->offset = 0;
20-
#elif defined(__wasip3__)
21-
dirp->stream = 0;
16+
#elif defined(__wasip2__) || defined(__wasip3__)
17+
dirent_close_streams(dirp);
2218
dirp->skip = 0;
2319
dirp->offset = 0;
2420
#else

libc-bottom-half/cloudlibc/src/libc/dirent/seekdir.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@ void seekdir(DIR *dirp, long loc) {
1313
// Mark entire buffer as processed to force a read of new data.
1414
// TODO(ed): We could prevent a read if the offset is in the buffer.
1515
dirp->buffer_used = dirp->buffer_processed = dirp->buffer_size;
16-
#elif defined(__wasip2__)
17-
dirp->stream.__handle = 0;
18-
dirp->skip = loc;
19-
dirp->offset = 0;
20-
#elif defined(__wasip3__)
21-
dirp->stream = 0;
16+
#elif defined(__wasip2__) || defined(__wasip3__)
17+
dirent_close_streams(dirp);
2218
dirp->skip = loc;
2319
dirp->offset = 0;
2420
#else

0 commit comments

Comments
 (0)