summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile56
-rw-r--r--README.md7
-rw-r--r--dlmalloc/src/malloc.c4
-rw-r--r--expected/wasm32-wasi-threads/defined-symbols.txt6
-rw-r--r--expected/wasm32-wasi-threads/predefined-macros.txt5
-rw-r--r--expected/wasm32-wasi/defined-symbols.txt1
-rw-r--r--expected/wasm32-wasi/predefined-macros.txt5
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/unistd/close.c16
-rw-r--r--libc-bottom-half/crt/crt1-reactor.c20
-rw-r--r--libc-bottom-half/headers/public/__header_sys_socket.h2
-rw-r--r--libc-bottom-half/headers/public/wasi/libc.h6
-rw-r--r--libc-bottom-half/sources/__wasilibc_fd_renumber.c22
-rw-r--r--libc-bottom-half/sources/__wasilibc_real.c2
-rw-r--r--libc-bottom-half/sources/preopens.c58
-rw-r--r--libc-top-half/musl/arch/wasm32/atomic_arch.h1
-rw-r--r--libc-top-half/musl/include/pthread.h6
-rw-r--r--libc-top-half/musl/src/env/__init_tls.c7
-rw-r--r--libc-top-half/musl/src/thread/pthread_create.c53
-rw-r--r--libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s17
19 files changed, 198 insertions, 96 deletions
diff --git a/Makefile b/Makefile
index 57975a7..00d26d3 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ MALLOC_IMPL ?= dlmalloc
# yes or no
BUILD_LIBC_TOP_HALF ?= yes
# The directory where we will store intermediate artifacts.
-OBJDIR ?= $(CURDIR)/build/$(TARGET_TRIPLE)
+OBJDIR ?= build/$(TARGET_TRIPLE)
# When the length is no larger than this threshold, we consider the
# overhead of bulk memory opcodes to outweigh the performance benefit,
@@ -43,13 +43,13 @@ endif
# These variables describe the locations of various files and directories in
# the source tree.
-DLMALLOC_DIR = $(CURDIR)/dlmalloc
+DLMALLOC_DIR = dlmalloc
DLMALLOC_SRC_DIR = $(DLMALLOC_DIR)/src
DLMALLOC_SOURCES = $(DLMALLOC_SRC_DIR)/dlmalloc.c
DLMALLOC_INC = $(DLMALLOC_DIR)/include
-EMMALLOC_DIR = $(CURDIR)/emmalloc
+EMMALLOC_DIR = emmalloc
EMMALLOC_SOURCES = $(EMMALLOC_DIR)/emmalloc.c
-LIBC_BOTTOM_HALF_DIR = $(CURDIR)/libc-bottom-half
+LIBC_BOTTOM_HALF_DIR = libc-bottom-half
LIBC_BOTTOM_HALF_CLOUDLIBC_SRC = $(LIBC_BOTTOM_HALF_DIR)/cloudlibc/src
LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC = $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/include
LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public
@@ -79,7 +79,7 @@ LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES = \
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/signal/psignal.c \
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/strsignal.c
LIBC_BOTTOM_HALF_CRT_SOURCES = $(wildcard $(LIBC_BOTTOM_HALF_DIR)/crt/*.c)
-LIBC_TOP_HALF_DIR = $(CURDIR)/libc-top-half
+LIBC_TOP_HALF_DIR = libc-top-half
LIBC_TOP_HALF_MUSL_DIR = $(LIBC_TOP_HALF_DIR)/musl
LIBC_TOP_HALF_MUSL_SRC_DIR = $(LIBC_TOP_HALF_MUSL_DIR)/src
LIBC_TOP_HALF_MUSL_INC = $(LIBC_TOP_HALF_MUSL_DIR)/include
@@ -262,6 +262,11 @@ LIBC_TOP_HALF_MUSL_SOURCES += \
thread/pthread_setcancelstate.c \
thread/pthread_setspecific.c \
thread/pthread_self.c \
+ thread/pthread_spin_destroy.c \
+ thread/pthread_spin_init.c \
+ thread/pthread_spin_lock.c \
+ thread/pthread_spin_trylock.c \
+ thread/pthread_spin_unlock.c \
thread/pthread_testcancel.c \
thread/sem_destroy.c \
thread/sem_getvalue.c \
@@ -320,6 +325,7 @@ ifeq ($(THREAD_MODEL), posix)
# Specify the tls-model until LLVM 15 is released (which should contain
# https://reviews.llvm.org/D130053).
CFLAGS += -mthread-model posix -pthread -ftls-model=local-exec
+ASMFLAGS += -matomics
# Include cloudlib's directory to access the structure definition of clockid_t
CFLAGS += -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)
@@ -341,8 +347,8 @@ CFLAGS += -isystem "$(SYSROOT_INC)"
# These variables describe the locations of various files and directories in
# the build tree.
-objs = $(patsubst $(CURDIR)/%.c,$(OBJDIR)/%.o,$(1))
-asmobjs = $(patsubst $(CURDIR)/%.s,$(OBJDIR)/%.o,$(1))
+objs = $(patsubst %.c,$(OBJDIR)/%.o,$(1))
+asmobjs = $(patsubst %.s,$(OBJDIR)/%.o,$(1))
DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES))
EMMALLOC_OBJS = $(call objs,$(EMMALLOC_SOURCES))
LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES))
@@ -371,6 +377,7 @@ LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS = $(call objs,$(LIBWASI_EMULATED_PROCESS_CL
LIBWASI_EMULATED_GETPID_OBJS = $(call objs,$(LIBWASI_EMULATED_GETPID_SOURCES))
LIBWASI_EMULATED_SIGNAL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_SOURCES))
LIBWASI_EMULATED_SIGNAL_MUSL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES))
+LIBC_BOTTOM_HALF_CRT_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_CRT_SOURCES))
# These variables describe the locations of various files and
# directories in the generated sysroot tree.
@@ -482,13 +489,13 @@ $(SYSROOT_LIB)/libwasi-emulated-signal.a: $(LIBWASI_EMULATED_SIGNAL_OBJS) $(LIBW
%.a:
@mkdir -p "$(@D)"
# On Windows, the commandline for the ar invocation got too long, so it needs to be split up.
- $(AR) crs $@ $(wordlist 1, 199, $^)
- $(AR) crs $@ $(wordlist 200, 399, $^)
- $(AR) crs $@ $(wordlist 400, 599, $^)
- $(AR) crs $@ $(wordlist 600, 799, $^)
+ $(AR) crs $@ $(wordlist 1, 199, $(sort $^))
+ $(AR) crs $@ $(wordlist 200, 399, $(sort $^))
+ $(AR) crs $@ $(wordlist 400, 599, $(sort $^))
+ $(AR) crs $@ $(wordlist 600, 799, $(sort $^))
# This might eventually overflow again, but at least it'll do so in a loud way instead of
# silently dropping the tail.
- $(AR) crs $@ $(wordlist 800, 100000, $^)
+ $(AR) crs $@ $(wordlist 800, 100000, $(sort $^))
$(MUSL_PRINTSCAN_OBJS): CFLAGS += \
-D__wasilibc_printscan_no_long_double \
@@ -509,19 +516,19 @@ $(BULK_MEMORY_OBJS): CFLAGS += \
$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS): CFLAGS += \
-D_WASI_EMULATED_SIGNAL
-$(OBJDIR)/%.long-double.o: $(CURDIR)/%.c include_dirs
+$(OBJDIR)/%.long-double.o: %.c include_dirs
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) -MD -MP -o $@ -c $<
-$(OBJDIR)/%.no-floating-point.o: $(CURDIR)/%.c include_dirs
+$(OBJDIR)/%.no-floating-point.o: %.c include_dirs
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) -MD -MP -o $@ -c $<
-$(OBJDIR)/%.o: $(CURDIR)/%.c include_dirs
+$(OBJDIR)/%.o: %.c include_dirs
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) -MD -MP -o $@ -c $<
-$(OBJDIR)/%.o: $(CURDIR)/%.s include_dirs
+$(OBJDIR)/%.o: %.s include_dirs
@mkdir -p "$(@D)"
$(CC) $(ASMFLAGS) -o $@ -c $<
@@ -577,15 +584,12 @@ include_dirs:
# Remove selected header files.
$(RM) $(patsubst %,$(SYSROOT_INC)/%,$(MUSL_OMIT_HEADERS))
-startup_files: include_dirs
+startup_files: include_dirs $(LIBC_BOTTOM_HALF_CRT_OBJS)
#
- # Build the startup files.
+ # Install the startup files (crt1.o etc).
#
- @mkdir -p "$(OBJDIR)"
- cd "$(OBJDIR)" && \
- $(CC) $(CFLAGS) -c $(LIBC_BOTTOM_HALF_CRT_SOURCES) -MD -MP && \
mkdir -p "$(SYSROOT_LIB)" && \
- mv *.o "$(SYSROOT_LIB)"
+ cp $(LIBC_BOTTOM_HALF_CRT_OBJS) "$(SYSROOT_LIB)"
libc: include_dirs \
$(SYSROOT_LIB)/libc.a \
@@ -668,6 +672,7 @@ check-symbols: startup_files libc
@#
@# TODO: Filter out __NO_MATH_ERRNO_ and a few __*WIDTH__ that are new to clang 14.
@# TODO: Filter out __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* that are new to clang 16.
+ @# TODO: Filter out __FPCLASS_* that are new to clang 17.
@# TODO: clang defined __FLT_EVAL_METHOD__ until clang 15, so we force-undefine it
@# for older versions.
@# TODO: Undefine __wasm_mutable_globals__ and __wasm_sign_ext__, that are new to
@@ -699,11 +704,16 @@ check-symbols: startup_files libc
| sed -e 's/__GNUC_VA_LIST $$/__GNUC_VA_LIST 1/' \
| grep -v '^#define __\(BOOL\|INT_\(LEAST\|FAST\)\(8\|16\|32\|64\)\|INT\|LONG\|LLONG\|SHRT\)_WIDTH__' \
| grep -v '^#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_\(1\|2\|4\|8\)' \
+ | grep -v '^#define __FPCLASS_' \
+ | grep -v '^#define NDEBUG' \
+ | grep -v '^#define __OPTIMIZE__' \
+ | grep -v '^#define assert' \
+ | grep -v '^#define __NO_INLINE__' \
> "$(SYSROOT_SHARE)/predefined-macros.txt"
# Check that the computed metadata matches the expected metadata.
# This ignores whitespace because on Windows the output has CRLF line endings.
- diff -wur "$(CURDIR)/expected/$(TARGET_TRIPLE)" "$(SYSROOT_SHARE)"
+ diff -wur "expected/$(TARGET_TRIPLE)" "$(SYSROOT_SHARE)"
install: finish
mkdir -p "$(INSTALL_DIR)"
diff --git a/README.md b/README.md
index 3068295..60307a1 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,10 @@ extra setup. This is one of the things [wasi-sdk] simplifies, as it includes
cross-compiled builds of compiler-rt, libc++.a, and libc++abi.a.
## Arch Linux AUR package
-For Arch Linux users, there's an unofficial AUR package tracking this git repo that can be installed under the name [wasi-libc-git].
+
+For Arch Linux users, there's an official [wasi-libc] package tracking this Git
+repository. You might want to install other [WASI related packages] as well.
[wasi-sdk]: https://github.com/WebAssembly/wasi-sdk
-[wasi-libc-git]: https://aur.archlinux.org/packages/wasi-libc-git/
+[wasi-libc]: https://archlinux.org/packages/community/any/wasi-libc/
+[WASI related packages]: https://archlinux.org/packages/?q=wasi-
diff --git a/dlmalloc/src/malloc.c b/dlmalloc/src/malloc.c
index 6e7a15c..c9c8ea6 100644
--- a/dlmalloc/src/malloc.c
+++ b/dlmalloc/src/malloc.c
@@ -2839,7 +2839,7 @@ static size_t traverse_and_check(mstate m);
#define treebin_at(M,i) (&((M)->treebins[i]))
/* assign tree index for size S to variable I. Use x86 asm if possible */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__) || defined(__wasm__))
#define compute_tree_index(S, I)\
{\
unsigned int X = S >> TREEBIN_SHIFT;\
@@ -2942,7 +2942,7 @@ static size_t traverse_and_check(mstate m);
/* index corresponding to given bit. Use x86 asm if possible */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__) || defined(__wasm__))
#define compute_bit2idx(X, I)\
{\
unsigned int J;\
diff --git a/expected/wasm32-wasi-threads/defined-symbols.txt b/expected/wasm32-wasi-threads/defined-symbols.txt
index 8dba0f1..c913f16 100644
--- a/expected/wasm32-wasi-threads/defined-symbols.txt
+++ b/expected/wasm32-wasi-threads/defined-symbols.txt
@@ -390,6 +390,7 @@ __wasilibc_nocwd_scandirat
__wasilibc_nocwd_symlinkat
__wasilibc_nocwd_utimensat
__wasilibc_open_nomode
+__wasilibc_populate_preopens
__wasilibc_pthread_self
__wasilibc_register_preopened_fd
__wasilibc_rename_newat
@@ -1044,6 +1045,11 @@ pthread_rwlockattr_setpshared
pthread_self
pthread_setcancelstate
pthread_setspecific
+pthread_spin_destroy
+pthread_spin_init
+pthread_spin_lock
+pthread_spin_trylock
+pthread_spin_unlock
pthread_testcancel
pthread_timedjoin_np
pthread_tryjoin_np
diff --git a/expected/wasm32-wasi-threads/predefined-macros.txt b/expected/wasm32-wasi-threads/predefined-macros.txt
index a9f2982..0fca3e4 100644
--- a/expected/wasm32-wasi-threads/predefined-macros.txt
+++ b/expected/wasm32-wasi-threads/predefined-macros.txt
@@ -1098,7 +1098,7 @@
#define MSG_BAND 0x04
#define MSG_HIPRI 0x01
#define MSG_PEEK __WASI_RIFLAGS_RECV_PEEK
-#define MSG_TRUNC __WASI_RIFLAGS_RECV_DATA_TRUNCATED
+#define MSG_TRUNC __WASI_ROFLAGS_RECV_DATA_TRUNCATED
#define MSG_WAITALL __WASI_RIFLAGS_RECV_WAITALL
#define MUXID_ALL (-1)
#define M_1_PI 0.31830988618379067154
@@ -1119,7 +1119,6 @@
#define NAN (0.0f/0.0f)
#define NBBY 8
#define NCARGS 131072
-#define NDEBUG 1
#define ND_NA_FLAG_OVERRIDE 0x00000020
#define ND_NA_FLAG_ROUTER 0x00000080
#define ND_NA_FLAG_SOLICITED 0x00000040
@@ -2685,7 +2684,6 @@
#define __OPENCL_MEMORY_SCOPE_SUB_GROUP 4
#define __OPENCL_MEMORY_SCOPE_WORK_GROUP 1
#define __OPENCL_MEMORY_SCOPE_WORK_ITEM 0
-#define __OPTIMIZE__ 1
#define __ORDER_BIG_ENDIAN__ 4321
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_PDP_ENDIAN__ 3412
@@ -3112,7 +3110,6 @@
#define and_eq &=
#define asin(x) __tg_real_complex(asin, (x))
#define asinh(x) __tg_real_complex(asinh, (x))
-#define assert(x) (void)0
#define atan(x) __tg_real_complex(atan, (x))
#define atan2(x,y) __tg_real_2(atan2, (x), (y))
#define atanh(x) __tg_real_complex(atanh, (x))
diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt
index a692632..6e74322 100644
--- a/expected/wasm32-wasi/defined-symbols.txt
+++ b/expected/wasm32-wasi/defined-symbols.txt
@@ -329,6 +329,7 @@ __wasilibc_nocwd_scandirat
__wasilibc_nocwd_symlinkat
__wasilibc_nocwd_utimensat
__wasilibc_open_nomode
+__wasilibc_populate_preopens
__wasilibc_register_preopened_fd
__wasilibc_rename_newat
__wasilibc_rename_oldat
diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt
index 234ad3c..d6cae22 100644
--- a/expected/wasm32-wasi/predefined-macros.txt
+++ b/expected/wasm32-wasi/predefined-macros.txt
@@ -1098,7 +1098,7 @@
#define MSG_BAND 0x04
#define MSG_HIPRI 0x01
#define MSG_PEEK __WASI_RIFLAGS_RECV_PEEK
-#define MSG_TRUNC __WASI_RIFLAGS_RECV_DATA_TRUNCATED
+#define MSG_TRUNC __WASI_ROFLAGS_RECV_DATA_TRUNCATED
#define MSG_WAITALL __WASI_RIFLAGS_RECV_WAITALL
#define MUXID_ALL (-1)
#define M_1_PI 0.31830988618379067154
@@ -1119,7 +1119,6 @@
#define NAN (0.0f/0.0f)
#define NBBY 8
#define NCARGS 131072
-#define NDEBUG 1
#define ND_NA_FLAG_OVERRIDE 0x00000020
#define ND_NA_FLAG_ROUTER 0x00000080
#define ND_NA_FLAG_SOLICITED 0x00000040
@@ -2648,7 +2647,6 @@
#define __OPENCL_MEMORY_SCOPE_SUB_GROUP 4
#define __OPENCL_MEMORY_SCOPE_WORK_GROUP 1
#define __OPENCL_MEMORY_SCOPE_WORK_ITEM 0
-#define __OPTIMIZE__ 1
#define __ORDER_BIG_ENDIAN__ 4321
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_PDP_ENDIAN__ 3412
@@ -3073,7 +3071,6 @@
#define and_eq &=
#define asin(x) __tg_real_complex(asin, (x))
#define asinh(x) __tg_real_complex(asinh, (x))
-#define assert(x) (void)0
#define atan(x) __tg_real_complex(atan, (x))
#define atan2(x,y) __tg_real_2(atan2, (x), (y))
#define atanh(x) __tg_real_complex(atanh, (x))
diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/close.c b/libc-bottom-half/cloudlibc/src/libc/unistd/close.c
deleted file mode 100644
index 2f5814b..0000000
--- a/libc-bottom-half/cloudlibc/src/libc/unistd/close.c
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
-//
-// SPDX-License-Identifier: BSD-2-Clause
-
-#include <wasi/api.h>
-#include <errno.h>
-#include <unistd.h>
-
-int close(int fildes) {
- __wasi_errno_t error = __wasi_fd_close(fildes);
- if (error != 0) {
- errno = error;
- return -1;
- }
- return 0;
-}
diff --git a/libc-bottom-half/crt/crt1-reactor.c b/libc-bottom-half/crt/crt1-reactor.c
index f507c9e..ea4a84f 100644
--- a/libc-bottom-half/crt/crt1-reactor.c
+++ b/libc-bottom-half/crt/crt1-reactor.c
@@ -1,7 +1,27 @@
+#if defined(_REENTRANT)
+#include <stdatomic.h>
+extern void __wasi_init_tp(void);
+#endif
extern void __wasm_call_ctors(void);
__attribute__((export_name("_initialize")))
void _initialize(void) {
+#if defined(_REENTRANT)
+ static volatile atomic_int initialized = 0;
+ int expected = 0;
+ if (!atomic_compare_exchange_strong(&initialized, &expected, 1)) {
+ __builtin_trap();
+ }
+
+ __wasi_init_tp();
+#else
+ static volatile int initialized = 0;
+ if (initialized != 0) {
+ __builtin_trap();
+ }
+ initialized = 1;
+#endif
+
// The linker synthesizes this to call constructors.
__wasm_call_ctors();
}
diff --git a/libc-bottom-half/headers/public/__header_sys_socket.h b/libc-bottom-half/headers/public/__header_sys_socket.h
index 9fa8684..77aaa1b 100644
--- a/libc-bottom-half/headers/public/__header_sys_socket.h
+++ b/libc-bottom-half/headers/public/__header_sys_socket.h
@@ -13,7 +13,7 @@
#define MSG_PEEK __WASI_RIFLAGS_RECV_PEEK
#define MSG_WAITALL __WASI_RIFLAGS_RECV_WAITALL
-#define MSG_TRUNC __WASI_RIFLAGS_RECV_DATA_TRUNCATED
+#define MSG_TRUNC __WASI_ROFLAGS_RECV_DATA_TRUNCATED
#define SOCK_DGRAM __WASI_FILETYPE_SOCKET_DGRAM
#define SOCK_STREAM __WASI_FILETYPE_SOCKET_STREAM
diff --git a/libc-bottom-half/headers/public/wasi/libc.h b/libc-bottom-half/headers/public/wasi/libc.h
index b50518b..18d8e9e 100644
--- a/libc-bottom-half/headers/public/wasi/libc.h
+++ b/libc-bottom-half/headers/public/wasi/libc.h
@@ -11,6 +11,12 @@ extern "C" {
struct stat;
struct timespec;
+/// Populate libc's preopen tables. This is normally done automatically
+/// just before it's needed, however if you call `__wasi_fd_renumber` or
+/// `__wasi_fd_close` directly, and you need the preopens to be accurate
+/// afterward, you should call this before doing so.
+void __wasilibc_populate_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).
diff --git a/libc-bottom-half/sources/__wasilibc_fd_renumber.c b/libc-bottom-half/sources/__wasilibc_fd_renumber.c
index aa9d8dc..47992e9 100644
--- a/libc-bottom-half/sources/__wasilibc_fd_renumber.c
+++ b/libc-bottom-half/sources/__wasilibc_fd_renumber.c
@@ -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;
@@ -11,3 +14,22 @@ int __wasilibc_fd_renumber(int fd, int newfd) {
}
return 0;
}
+
+int close(int fd) {
+ // Scan the preopen fds before making any changes.
+ __wasilibc_populate_preopens();
+
+ __wasi_errno_t error = __wasi_fd_close(fd);
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+
+ return 0;
+}
+
+weak void __wasilibc_populate_preopens(void) {
+ // This version does nothing. It may be overridden by a version which does
+ // something if `__wasilibc_find_abspath` or `__wasilibc_find_relpath` are
+ // used.
+}
diff --git a/libc-bottom-half/sources/__wasilibc_real.c b/libc-bottom-half/sources/__wasilibc_real.c
index d2e6b71..186de01 100644
--- a/libc-bottom-half/sources/__wasilibc_real.c
+++ b/libc-bottom-half/sources/__wasilibc_real.c
@@ -662,7 +662,7 @@ __wasi_errno_t __wasi_sock_shutdown(
#ifdef _REENTRANT
int32_t __imported_wasi_thread_spawn(int32_t arg0) __attribute__((
__import_module__("wasi"),
- __import_name__("thread_spawn")
+ __import_name__("thread-spawn")
));
int32_t __wasi_thread_spawn(void* start_arg) {
diff --git a/libc-bottom-half/sources/preopens.c b/libc-bottom-half/sources/preopens.c
index 7293c8c..b495433 100644
--- a/libc-bottom-half/sources/preopens.c
+++ b/libc-bottom-half/sources/preopens.c
@@ -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 == '/')
@@ -219,13 +231,20 @@ int __wasilibc_find_abspath(const char *path,
return fd;
}
-/// This is referenced by weak reference from crt1.c and lives in the same
-/// source file as `__wasilibc_find_relpath` so that it's linked in when it's
-/// needed.
-// Concerning the 51 -- see the comment by the constructor priority in
-// libc-bottom-half/sources/environ.c.
-__attribute__((constructor(51)))
-static void __wasilibc_populate_preopens(void) {
+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) {
@@ -249,7 +268,7 @@ static void __wasilibc_populate_preopens(void) {
goto oserr;
prefix[prestat.u.dir.pr_name_len] = '\0';
- if (internal_register_preopened_fd(fd, prefix) != 0)
+ if (internal_register_preopened_fd_unlocked(fd, prefix) != 0)
goto software;
free(prefix);
@@ -260,6 +279,11 @@ static void __wasilibc_populate_preopens(void) {
}
}
+ // Preopens are now initialized.
+ preopens_populated = true;
+
+ UNLOCK(lock);
+
return;
oserr:
_Exit(EX_OSERR);
diff --git a/libc-top-half/musl/arch/wasm32/atomic_arch.h b/libc-top-half/musl/arch/wasm32/atomic_arch.h
index dd9428c..c24ce2d 100644
--- a/libc-top-half/musl/arch/wasm32/atomic_arch.h
+++ b/libc-top-half/musl/arch/wasm32/atomic_arch.h
@@ -1,4 +1,3 @@
-#define a_barrier() (__sync_synchronize())
#define a_cas(p, t, s) (__sync_val_compare_and_swap((p), (t), (s)))
#define a_crash() (__builtin_trap())
#define a_clz_32 __builtin_clz
diff --git a/libc-top-half/musl/include/pthread.h b/libc-top-half/musl/include/pthread.h
index b14fe82..05101e8 100644
--- a/libc-top-half/musl/include/pthread.h
+++ b/libc-top-half/musl/include/pthread.h
@@ -55,15 +55,9 @@ extern "C" {
#define PTHREAD_PROCESS_SHARED 1
-#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#define PTHREAD_MUTEX_INITIALIZER {{{0}}}
#define PTHREAD_RWLOCK_INITIALIZER {{{0}}}
#define PTHREAD_COND_INITIALIZER {{{0}}}
-#else
-#define PTHREAD_MUTEX_INITIALIZER 0
-#define PTHREAD_RWLOCK_INITIALIZER 0
-#define PTHREAD_COND_INITIALIZER 0
-#endif
#define PTHREAD_ONCE_INIT 0
diff --git a/libc-top-half/musl/src/env/__init_tls.c b/libc-top-half/musl/src/env/__init_tls.c
index ece8d24..c3e407c 100644
--- a/libc-top-half/musl/src/env/__init_tls.c
+++ b/libc-top-half/musl/src/env/__init_tls.c
@@ -47,10 +47,9 @@ static inline void setup_default_stack_size()
stack_size = sp > &__global_base ? &__heap_base - &__data_end : (ptrdiff_t)&__global_base;
}
- if (stack_size > __default_stacksize)
- __default_stacksize =
- stack_size < DEFAULT_STACK_MAX ?
- stack_size : DEFAULT_STACK_MAX;
+ __default_stacksize =
+ stack_size < DEFAULT_STACK_MAX ?
+ stack_size : DEFAULT_STACK_MAX;
}
void __wasi_init_tp() {
diff --git a/libc-top-half/musl/src/thread/pthread_create.c b/libc-top-half/musl/src/thread/pthread_create.c
index 676e2cc..5de9f5a 100644
--- a/libc-top-half/musl/src/thread/pthread_create.c
+++ b/libc-top-half/musl/src/thread/pthread_create.c
@@ -60,6 +60,17 @@ void __tl_sync(pthread_t td)
if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0);
}
+#ifndef __wasilibc_unmodified_upstream
+static void *map_base_deferred_free;
+
+static void process_map_base_deferred_free()
+{
+ /* called with __tl_lock held */
+ free(map_base_deferred_free);
+ map_base_deferred_free = NULL;
+}
+#endif
+
#ifdef __wasilibc_unmodified_upstream
_Noreturn void __pthread_exit(void *result)
#else
@@ -164,14 +175,6 @@ static void __pthread_exit(void *result)
self->prev->next = self->next;
self->prev = self->next = self;
-#ifndef __wasilibc_unmodified_upstream
- /* On Linux, the thread is created with CLONE_CHILD_CLEARTID,
- * and this lock will unlock by kernel when this thread terminates.
- * So we should unlock it here in WebAssembly.
- * See also set_tid_address(2) */
- __tl_unlock();
-#endif
-
#ifdef __wasilibc_unmodified_upstream
if (state==DT_DETACHED && self->map_base) {
/* Detached threads must block even implementation-internal
@@ -190,10 +193,17 @@ static void __pthread_exit(void *result)
}
#else
if (state==DT_DETACHED && self->map_base) {
- // __syscall(SYS_exit) would unlock the thread, list
- // do it manually here
- __tl_unlock();
- free(self->map_base);
+ /* As we use malloc/free which is considerably more complex
+ * than mmap/munmap to call and can even require a valid
+ * thread context, it's difficult to implement __unmapself.
+ *
+ * Here we take an alternative approach which simply defers
+ * the deallocation. An obvious downside of this approach is
+ * that it keeps the stack longer. (possibly forever.)
+ * To avoid wasting too much memory, we only defer a single
+ * item at most. */
+ process_map_base_deferred_free();
+ map_base_deferred_free = self->map_base;
// Can't use `exit()` here, because it is too high level
return;
}
@@ -212,10 +222,15 @@ static void __pthread_exit(void *result)
#ifdef __wasilibc_unmodified_upstream
for (;;) __syscall(SYS_exit, 0);
#else
- // __syscall(SYS_exit) would unlock the thread, list
- // do it manually here
- __tl_unlock();
// Can't use `exit()` here, because it is too high level
+
+ /* On Linux, the thread is created with CLONE_CHILD_CLEARTID,
+ * and the lock (__thread_list_lock) will be unlocked by kernel when
+ * this thread terminates.
+ * See also set_tid_address(2)
+ *
+ * In WebAssembly, we leave it to wasi_thread_start instead.
+ */
#endif
}
@@ -430,6 +445,14 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
if (map == MAP_FAILED) goto fail;
}
#else
+ /* Process the deferred free request if any before
+ * allocationg a new one. Hopefully it enables a reuse of the memory.
+ *
+ * Note: We can't perform a simple "handoff" becasue allocation
+ * sizes might be different. (eg. the stack size might differ) */
+ __tl_lock();
+ process_map_base_deferred_free();
+ __tl_unlock();
map = malloc(size);
if (!map) goto fail;
#endif
diff --git a/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s b/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s
index 0fe9854..7a480b8 100644
--- a/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s
+++ b/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s
@@ -28,4 +28,21 @@ wasi_thread_start:
local.get 1 # start_arg
call __wasi_thread_start_C
+ # Unlock thread list. (as CLONE_CHILD_CLEARTID would do for Linux)
+ #
+ # Note: once we unlock the thread list, our "map_base" can be freed
+ # by a joining thread. It's safe as we are in ASM and no longer use
+ # our C stack or pthread_t. It's impossible to do this safely in C
+ # because there is no way to tell the C compiler not to use C stack.
+ i32.const __thread_list_lock
+ i32.const 0
+ i32.atomic.store 0
+ # As an optimization, we can check tl_lock_waiters here.
+ # But for now, simply wake up unconditionally as
+ # CLONE_CHILD_CLEARTID does.
+ i32.const __thread_list_lock
+ i32.const 1
+ memory.atomic.notify 0
+ drop
+
end_function