Re-add lazy preopen changes

This commit is contained in:
Frank Denis 2024-04-12 22:51:52 +02:00 committed by Alex Rønne Petersen
parent 3f4c43b0aa
commit 8a8da49b52
No known key found for this signature in database
5 changed files with 109 additions and 10 deletions

View file

@ -17,6 +17,10 @@ struct timespec;
/// afterward, you should call this before doing so.
void __wasilibc_populate_preopens(void);
/// Reset the preopens table to an uninitialized state, forcing it to be
/// reinitialized next time it is needed.
void __wasilibc_reset_preopens(void);
/// Register the given pre-opened file descriptor under the given path.
///
/// This function does not take ownership of `prefix` (it makes its own copy).

View file

@ -4,6 +4,9 @@
#include <unistd.h>
int __wasilibc_fd_renumber(int fd, int newfd) {
// Scan the preopen fds before making any changes.
__wasilibc_populate_preopens();
__wasi_errno_t error = __wasi_fd_renumber(fd, newfd);
if (error != 0) {
errno = error;

View file

@ -25,6 +25,7 @@ typedef struct preopen {
} preopen;
/// A simple growable array of `preopen`.
static _Atomic _Bool preopens_populated = false;
static preopen *preopens;
static size_t num_preopens;
static size_t preopen_capacity;
@ -100,12 +101,9 @@ static const char *strip_prefixes(const char *path) {
return path;
}
/// Register the given preopened file descriptor under the given path.
///
/// This function takes ownership of `prefix`.
static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) {
LOCK(lock);
/// Similar to `internal_register_preopened_fd_unlocked` but does not
/// take a lock.
static int internal_register_preopened_fd_unlocked(__wasi_fd_t fd, const char *relprefix) {
// Check preconditions.
assert_invariants();
assert(fd != AT_FDCWD);
@ -113,22 +111,32 @@ static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix)
assert(relprefix != NULL);
if (num_preopens == preopen_capacity && resize() != 0) {
UNLOCK(lock);
return -1;
}
char *prefix = strdup(strip_prefixes(relprefix));
if (prefix == NULL) {
UNLOCK(lock);
return -1;
}
preopens[num_preopens++] = (preopen) { prefix, fd, };
assert_invariants();
UNLOCK(lock);
return 0;
}
/// Register the given preopened file descriptor under the given path.
///
/// This function takes ownership of `prefix`.
static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) {
LOCK(lock);
int r = internal_register_preopened_fd_unlocked(fd, relprefix);
UNLOCK(lock);
return r;
}
/// Are the `prefix_len` bytes pointed to by `prefix` a prefix of `path`?
static bool prefix_matches(const char *prefix, size_t prefix_len, const char *path) {
// Allow an empty string as a prefix of any relative path.
@ -152,6 +160,8 @@ static bool prefix_matches(const char *prefix, size_t prefix_len, const char *pa
// See the documentation in libc.h
int __wasilibc_register_preopened_fd(int fd, const char *prefix) {
__wasilibc_populate_preopens();
return internal_register_preopened_fd((__wasi_fd_t)fd, prefix);
}
@ -172,6 +182,8 @@ int __wasilibc_find_relpath(const char *path,
int __wasilibc_find_abspath(const char *path,
const char **abs_prefix,
const char **relative_path) {
__wasilibc_populate_preopens();
// Strip leading `/` characters, the prefixes we're mataching won't have
// them.
while (*path == '/')
@ -218,3 +230,84 @@ int __wasilibc_find_abspath(const char *path,
*relative_path = computed;
return fd;
}
__attribute__((constructor(51)))
void __wasilibc_populate_preopens(void) {
// Fast path: If the preopens are already initialized, do nothing.
if (preopens_populated) {
return;
}
LOCK(lock);
// Check whether another thread initialized the preopens already.
if (preopens_populated) {
UNLOCK(lock);
return;
}
// Skip stdin, stdout, and stderr, and count up until we reach an invalid
// file descriptor.
for (__wasi_fd_t fd = 3; fd != 0; ++fd) {
__wasi_prestat_t prestat;
__wasi_errno_t ret = __wasi_fd_prestat_get(fd, &prestat);
if (ret == __WASI_ERRNO_BADF)
break;
if (ret != __WASI_ERRNO_SUCCESS)
goto oserr;
switch (prestat.tag) {
case __WASI_PREOPENTYPE_DIR: {
char *prefix = malloc(prestat.u.dir.pr_name_len + 1);
if (prefix == NULL)
goto software;
// TODO: Remove the cast on `prefix` once the witx is updated with
// char8 support.
ret = __wasi_fd_prestat_dir_name(fd, (uint8_t *)prefix,
prestat.u.dir.pr_name_len);
if (ret != __WASI_ERRNO_SUCCESS)
goto oserr;
prefix[prestat.u.dir.pr_name_len] = '\0';
if (internal_register_preopened_fd_unlocked(fd, prefix) != 0)
goto software;
free(prefix);
break;
}
default:
break;
}
}
// Preopens are now initialized.
preopens_populated = true;
UNLOCK(lock);
return;
oserr:
_Exit(EX_OSERR);
software:
_Exit(EX_SOFTWARE);
}
void __wasilibc_reset_preopens(void) {
LOCK(lock);
if (num_preopens) {
for (int i = 0; i < num_preopens; ++i) {
free((void*) preopens[i].prefix);
}
free(preopens);
}
preopens_populated = false;
preopens = NULL;
num_preopens = 0;
preopen_capacity = 0;
assert_invariants();
UNLOCK(lock);
}

View file

@ -463,7 +463,6 @@ const libc_bottom_half_src_files = [_][]const u8{
"wasi/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/time/nanosleep.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/time/time.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/fdatasync.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/fsync.c",