From 6e03994f426d44e2e5ed7b8a824a61bb80f1cd1b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 17:32:34 +0000 Subject: [PATCH 01/28] Pass --generate-threading-helpers for WASIP3 --- cmake/bindings.cmake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/bindings.cmake b/cmake/bindings.cmake index 15b8d0593..490aa5df9 100644 --- a/cmake/bindings.cmake +++ b/cmake/bindings.cmake @@ -15,8 +15,8 @@ if(WIT_BINDGEN_EXECUTABLE) OUTPUT_VARIABLE WIT_BINDGEN_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - if (NOT (WIT_BINDGEN_VERSION MATCHES "0\\.51\\.0")) - message(WARNING "wit-bindgen version 0.51.0 is required, found: ${WIT_BINDGEN_VERSION}") + if (NOT (WIT_BINDGEN_VERSION MATCHES "0\\.53\\.1")) + message(WARNING "wit-bindgen version 0.53.1 is required, found: ${WIT_BINDGEN_VERSION}") set(WIT_BINDGEN_EXECUTABLE "") endif() endif() @@ -26,7 +26,7 @@ if (NOT WIT_BINDGEN_EXECUTABLE) ba_download( wit-bindgen "https://github.com/bytecodealliance/wit-bindgen" - "0.51.0" + "0.53.1" ) ExternalProject_Get_Property(wit-bindgen SOURCE_DIR) set(wit_bindgen "${SOURCE_DIR}/wit-bindgen") @@ -87,6 +87,7 @@ add_custom_target( --rename-world wasip3 --type-section-suffix __wasi_libc --world wasi:cli/imports@${wasip3-version} + --generate-threading-helpers --rename wasi:clocks/monotonic-clock@${wasip3-version}=monotonic_clock --rename wasi:clocks/system-clock@${wasip3-version}=system_clock --rename wasi:filesystem/preopens@${wasip3-version}=filesystem_preopens @@ -133,4 +134,4 @@ function(wit_bindgen_edit p) endfunction() wit_bindgen_edit(p2) -wit_bindgen_edit(p3) +wit_bindgen_edit(p3) \ No newline at end of file From 776691c31fb255f1ce19160353d1a2bfced928dd Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 17:33:13 +0000 Subject: [PATCH 02/28] Newline --- cmake/bindings.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/bindings.cmake b/cmake/bindings.cmake index 490aa5df9..ed1236ec0 100644 --- a/cmake/bindings.cmake +++ b/cmake/bindings.cmake @@ -134,4 +134,4 @@ function(wit_bindgen_edit p) endfunction() wit_bindgen_edit(p2) -wit_bindgen_edit(p3) \ No newline at end of file +wit_bindgen_edit(p3) From 1e176a0b734ca86df532fc741367c20cdc8c4717 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 17:35:06 +0000 Subject: [PATCH 03/28] Generate bindings --- .../headers/public/wasi/__generated_wasip2.h | 2 +- .../headers/public/wasi/__generated_wasip3.h | 18 +++- libc-bottom-half/sources/wasip2.c | 2 +- .../sources/wasip2_component_type.o | Bin 10846 -> 10846 bytes libc-bottom-half/sources/wasip3.c | 101 +++++++++++++++++- .../sources/wasip3_component_type.o | Bin 8099 -> 8099 bytes 6 files changed, 119 insertions(+), 4 deletions(-) diff --git a/libc-bottom-half/headers/public/wasi/__generated_wasip2.h b/libc-bottom-half/headers/public/wasi/__generated_wasip2.h index e4f14db97..2a8718739 100644 --- a/libc-bottom-half/headers/public/wasi/__generated_wasip2.h +++ b/libc-bottom-half/headers/public/wasi/__generated_wasip2.h @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.51.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.53.1. DO NOT EDIT! #ifndef __BINDINGS_WASIP2_H #define __BINDINGS_WASIP2_H #ifdef __cplusplus diff --git a/libc-bottom-half/headers/public/wasi/__generated_wasip3.h b/libc-bottom-half/headers/public/wasi/__generated_wasip3.h index f9f04db25..2a5d526ce 100644 --- a/libc-bottom-half/headers/public/wasi/__generated_wasip3.h +++ b/libc-bottom-half/headers/public/wasi/__generated_wasip3.h @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.51.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.53.1. DO NOT EDIT! #ifndef __BINDINGS_WASIP3_H #define __BINDINGS_WASIP3_H #ifdef __cplusplus @@ -80,6 +80,22 @@ void wasip3_context_set_0(void* value); void wasip3_thread_yield(void); +void* wasip3_context_get_1(void); +void wasip3_context_set_1(void* value); +uint32_t wasip3_thread_yield_cancellable(void); +uint32_t wasip3_thread_index(void); +uint32_t wasip3_thread_new_indirect(void (*start_function)(void*), void* arg); +void wasip3_thread_suspend_to(uint32_t thread); +uint32_t wasip3_thread_suspend_to_cancellable(uint32_t thread); +void wasip3_thread_suspend_to_suspended(uint32_t thread); +uint32_t wasip3_thread_suspend_to_suspended_cancellable(uint32_t thread); +void wasip3_thread_unsuspend(uint32_t thread); +void wasip3_thread_yield_to_suspended(uint32_t thread); +uint32_t wasip3_thread_yield_to_suspended_cancellable(uint32_t thread); +void wasip3_thread_suspend(void); +uint32_t wasip3_thread_suspend_cancellable(void); + + typedef struct { wasip3_string_t f0; diff --git a/libc-bottom-half/sources/wasip2.c b/libc-bottom-half/sources/wasip2.c index ef3f67ba2..da2a5f141 100644 --- a/libc-bottom-half/sources/wasip2.c +++ b/libc-bottom-half/sources/wasip2.c @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.51.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.53.1. DO NOT EDIT! #include "wasi/wasip2.h" #include #include diff --git a/libc-bottom-half/sources/wasip2_component_type.o b/libc-bottom-half/sources/wasip2_component_type.o index abbd242946ebf1c4c3b4933cb92293b05f6a0461..5f85d8c870715ab8d86771b0d2e9457b58533518 100644 GIT binary patch delta 36 rcmcZ?axY{9x0Zydo*{2}W{GZ6W?o8qYMyQ~n}MFGv7X^%Wi4v}=zj|_ delta 36 rcmcZ?axY{9x0Zy7o&j%pW{GZ6W?o8qYMyQ~n}MFGp`O8HWi4v}=r#*1 diff --git a/libc-bottom-half/sources/wasip3.c b/libc-bottom-half/sources/wasip3.c index 26b92a86a..8b0f3d960 100644 --- a/libc-bottom-half/sources/wasip3.c +++ b/libc-bottom-half/sources/wasip3.c @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.51.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.53.1. DO NOT EDIT! #include "wasi/wasip3.h" #include #include @@ -1142,6 +1142,105 @@ void wasip3_thread_yield(void) { } +__attribute__((__import_module__("$root"), __import_name__("[context-get-1]"))) +extern void* __context_get_1(void); + +void* wasip3_context_get_1(void) { + return __context_get_1(); +} + +__attribute__((__import_module__("$root"), __import_name__("[context-set-1]"))) +extern void __context_set_1(void*); + +void wasip3_context_set_1(void* value) { + __context_set_1(value); +} + +__attribute__((__import_module__("$root"), __import_name__("[cancellable][thread-yield]"))) +extern uint32_t __thread_yield_cancellable(void); + +uint32_t wasip3_thread_yield_cancellable(void) { + return __thread_yield_cancellable(); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-index]"))) +extern uint32_t __thread_index(void); + +uint32_t wasip3_thread_index(void) { + return __thread_index(); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-new-indirect-v0]"))) +extern uint32_t __thread_new_indirect(uint32_t, void*); + +uint32_t wasip3_thread_new_indirect(void (*start_function)(void*), void* arg) { + return __thread_new_indirect((uint32_t)(uintptr_t)start_function, arg + ); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-suspend-to-suspended]"))) +extern uint32_t __thread_suspend_to_suspended(uint32_t); + +void wasip3_thread_suspend_to_suspended(uint32_t thread) { + __thread_suspend_to_suspended(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[cancellable][thread-suspend-to-suspended]"))) +extern uint32_t __thread_suspend_to_suspended_cancellable(uint32_t); + +uint32_t wasip3_thread_suspend_to_suspended_cancellable(uint32_t thread) { + return __thread_suspend_to_suspended_cancellable(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-suspend-to]"))) +extern uint32_t __thread_suspend_to(uint32_t); + +void wasip3_thread_suspend_to(uint32_t thread) { + __thread_suspend_to(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[cancellable][thread-suspend-to]"))) +extern uint32_t __thread_suspend_to_cancellable(uint32_t); + +uint32_t wasip3_thread_suspend_to_cancellable(uint32_t thread) { + return __thread_suspend_to_cancellable(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-unsuspend]"))) +extern void __thread_unsuspend(uint32_t); + +void wasip3_thread_unsuspend(uint32_t thread) { + __thread_unsuspend(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-yield-to-suspended]"))) +extern uint32_t __thread_yield_to_suspended(uint32_t); + +void wasip3_thread_yield_to_suspended(uint32_t thread) { + __thread_yield_to_suspended(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[cancellable][thread-yield-to-suspended]"))) +extern uint32_t __thread_yield_to_suspended_cancellable(uint32_t); + +uint32_t wasip3_thread_yield_to_suspended_cancellable(uint32_t thread) { + return __thread_yield_to_suspended_cancellable(thread); +} + +__attribute__((__import_module__("$root"), __import_name__("[thread-suspend]"))) +extern uint32_t __thread_suspend(void); + +void wasip3_thread_suspend(void) { + __thread_suspend(); +} + +__attribute__((__import_module__("$root"), __import_name__("[cancellable][thread-suspend]"))) +extern uint32_t __thread_suspend_cancellable(void); +uint32_t wasip3_thread_suspend_cancellable(void) { + return __thread_suspend_cancellable(); +} + + // Component Adapters diff --git a/libc-bottom-half/sources/wasip3_component_type.o b/libc-bottom-half/sources/wasip3_component_type.o index 68f4f3604b601e2b750b65bc5532d01a799cf67a..e92156ffbbf4554b4083803e095e23a5cdefae0b 100644 GIT binary patch delta 36 rcmZ2%zu105fV_mMo*{2}W{GZ6W?o8qYMyQ~n}MFGv7X`N40&q++LH?f delta 36 rcmZ2%zu105fV_l>o&j%pW{GZ6W?o8qYMyQ~n}MFGp`O9y40&q++DZ!m From 418a2cf8d9ce5b3cb2cb6829562bd80c15d34d26 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 18:05:40 +0000 Subject: [PATCH 04/28] Locks --- CMakeLists.txt | 1 + .../cloudlibc/src/libc/sched/sched_yield.c | 8 ++++ .../headers/public/wasi/version.h.in | 1 + libc-bottom-half/sources/getcwd.c | 16 +++---- libc-bottom-half/sources/preopens.c | 30 ++++++------ libc-top-half/musl/src/exit/at_quick_exit.c | 16 ++++--- libc-top-half/musl/src/exit/atexit.c | 20 ++++---- libc-top-half/musl/src/internal/locale_impl.h | 3 +- libc-top-half/musl/src/internal/lock.h | 47 ++++++++++++++++--- .../musl/src/internal/pthread_impl.h | 35 +++++--------- libc-top-half/musl/src/internal/stdio_impl.h | 14 +++++- libc-top-half/musl/src/locale/locale_map.c | 4 +- libc-top-half/musl/src/locale/newlocale.c | 4 +- libc-top-half/musl/src/locale/setlocale.c | 10 ++-- .../musl/src/malloc/oldmalloc/malloc.c | 11 +++++ libc-top-half/musl/src/prng/random.c | 22 +++++---- libc-top-half/musl/src/stdio/__fdopen.c | 2 +- libc-top-half/musl/src/stdio/__fopen_rb_ca.c | 2 +- libc-top-half/musl/src/stdio/__lockfile.c | 24 ++++++++++ libc-top-half/musl/src/stdio/fmemopen.c | 2 +- libc-top-half/musl/src/stdio/ftrylockfile.c | 38 +++++++++++++-- libc-top-half/musl/src/stdio/getc.h | 13 ++++- libc-top-half/musl/src/stdio/ofl.c | 8 ++-- libc-top-half/musl/src/stdio/open_memstream.c | 2 +- .../musl/src/stdio/open_wmemstream.c | 2 +- libc-top-half/musl/src/stdio/putc.h | 18 ++++++- libc-top-half/musl/src/stdio/stderr.c | 2 +- libc-top-half/musl/src/stdio/stdin.c | 2 +- libc-top-half/musl/src/stdio/stdout.c | 2 +- libc-top-half/musl/src/stdio/vdprintf.c | 2 +- libc-top-half/musl/src/stdio/vsscanf.c | 5 +- libc-top-half/musl/src/stdio/vswscanf.c | 5 +- libc-top-half/musl/src/stdlib/wcstod.c | 2 +- libc-top-half/musl/src/stdlib/wcstol.c | 2 +- .../musl/src/thread/coop-threads/__lock.c | 38 +++++++++++++++ .../musl/src/thread/coop-threads/__wait.c | 47 +++++++++++++++++++ 36 files changed, 344 insertions(+), 116 deletions(-) create mode 100644 libc-top-half/musl/src/thread/coop-threads/__lock.c create mode 100644 libc-top-half/musl/src/thread/coop-threads/__wait.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c48f41b15..86793fdc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,7 @@ elseif(WASI STREQUAL "p2") set(__wasip2__ ON) elseif(WASI STREQUAL "p3") set(__wasip3__ ON) + set(__wasi_cooperative_threads__ ON) else() message(FATAL_ERROR "Unknown WASI version: ${WASI}") endif() diff --git a/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c b/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c index fc13322b6..c4b298e33 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c +++ b/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c @@ -7,6 +7,14 @@ #include int sched_yield(void) { +#ifdef __wasi_cooperative_threads__ + #ifdef __wasip3__ + wasip3_thread_yield(); + return 0; + #else + #error "Unknown WASI version" + #endif +#elif defined(__wasip1__) #ifdef __wasip1__ __wasi_errno_t error = __wasi_sched_yield(); if (error != 0) { diff --git a/libc-bottom-half/headers/public/wasi/version.h.in b/libc-bottom-half/headers/public/wasi/version.h.in index 2cca21efc..8da5d9991 100644 --- a/libc-bottom-half/headers/public/wasi/version.h.in +++ b/libc-bottom-half/headers/public/wasi/version.h.in @@ -10,6 +10,7 @@ #cmakedefine __wasip1__ #cmakedefine __wasip2__ #cmakedefine __wasip3__ +#cmakedefine __wasi_cooperative_threads__ #cmakedefine __wasi_sdk_major__ @__wasi_sdk_major__@ #cmakedefine __wasi_sdk_version__ "@__wasi_sdk_version__@" diff --git a/libc-bottom-half/sources/getcwd.c b/libc-bottom-half/sources/getcwd.c index 8b0b0b746..576508620 100644 --- a/libc-bottom-half/sources/getcwd.c +++ b/libc-bottom-half/sources/getcwd.c @@ -7,32 +7,28 @@ char *__wasilibc_cwd = "/"; #ifdef _REENTRANT -static volatile int lock[1]; -void __wasilibc_cwd_lock(void) { LOCK(lock); } -void __wasilibc_cwd_unlock(void) { UNLOCK(lock); } -#else -#define __wasilibc_cwd_lock() (void)0 -#define __wasilibc_cwd_unlock() (void)0 +static __lock_t lock[1]; #endif char *getcwd(char *buf, size_t size) { - __wasilibc_cwd_lock(); + // Critical section contains no yield points, so we can use weak locks. + WEAK_LOCK(lock); if (!buf) { buf = strdup(__wasilibc_cwd); if (!buf) { errno = ENOMEM; - __wasilibc_cwd_unlock(); + WEAK_UNLOCK(lock); return NULL; } } else { size_t len = strlen(__wasilibc_cwd); if (size < len + 1) { errno = ERANGE; - __wasilibc_cwd_unlock(); + WEAK_UNLOCK(lock); return NULL; } strcpy(buf, __wasilibc_cwd); } - __wasilibc_cwd_unlock(); + WEAK_UNLOCK(lock); return buf; } diff --git a/libc-bottom-half/sources/preopens.c b/libc-bottom-half/sources/preopens.c index cf91ac016..84738c53f 100644 --- a/libc-bottom-half/sources/preopens.c +++ b/libc-bottom-half/sources/preopens.c @@ -21,6 +21,12 @@ #include #endif +/// Access to the the above preopen must be protected in the presence of +/// threads. +#ifdef _REENTRANT +static __lock_t lock[1]; +#endif + #if defined(__wasip1__) typedef struct { __wasi_fd_t fd; @@ -96,12 +102,6 @@ static preopen *preopens; static size_t num_preopens; static size_t preopen_capacity; -/// Access to the the above preopen must be protected in the presence of -/// threads. -#ifdef _REENTRANT -static volatile int lock[1]; -#endif - #ifdef NDEBUG #define assert_invariants() // assertions disabled #else @@ -220,11 +220,11 @@ static bool prefix_matches(const char *prefix, size_t prefix_len, /// This function takes ownership of `prefix`. static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) { - LOCK(lock); + STRONG_LOCK(lock); int r = internal_register_preopened_fd_unlocked(fd, relprefix); - UNLOCK(lock); + STRONG_UNLOCK(lock); return r; } @@ -263,7 +263,7 @@ int __wasilibc_find_abspath(const char *path, const char **abs_prefix, // recently added preopens take precedence over less recently addded ones. size_t match_len = 0; int fd = -1; - LOCK(lock); + STRONG_LOCK(lock); for (size_t i = num_preopens; i > 0; --i) { const preopen *pre = &preopens[i - 1]; const char *prefix = pre->prefix; @@ -278,7 +278,7 @@ int __wasilibc_find_abspath(const char *path, const char **abs_prefix, *abs_prefix = prefix; } } - UNLOCK(lock); + STRONG_UNLOCK(lock); if (fd == -1) { errno = ENOENT; @@ -306,11 +306,11 @@ void __wasilibc_populate_preopens(void) { return; } - LOCK(lock); + STRONG_LOCK(lock); // Check whether another thread initialized the preopens already. if (preopens_populated) { - UNLOCK(lock); + STRONG_UNLOCK(lock); return; } @@ -381,7 +381,7 @@ void __wasilibc_populate_preopens(void) { // Preopens are now initialized. preopens_populated = true; - UNLOCK(lock); + STRONG_UNLOCK(lock); return; #ifdef __wasip1__ @@ -393,7 +393,7 @@ void __wasilibc_populate_preopens(void) { } void __wasilibc_reset_preopens(void) { - LOCK(lock); + STRONG_LOCK(lock); if (num_preopens) { for (int i = 0; i < num_preopens; ++i) { @@ -410,5 +410,5 @@ void __wasilibc_reset_preopens(void) { assert_invariants(); - UNLOCK(lock); + STRONG_UNLOCK(lock); } diff --git a/libc-top-half/musl/src/exit/at_quick_exit.c b/libc-top-half/musl/src/exit/at_quick_exit.c index 429d0b033..8cfffc426 100644 --- a/libc-top-half/musl/src/exit/at_quick_exit.c +++ b/libc-top-half/musl/src/exit/at_quick_exit.c @@ -8,28 +8,30 @@ static void (*funcs[COUNT])(void); static int count; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -static volatile int lock[1]; -volatile int *const __at_quick_exit_lockptr = lock; +// All locks here can be weak, because the locking is only needed to protect against +// concurrent manipulation of the handler table, which hits no context switch points. +static __lock_t lock[1]; +__lock_t *const __at_quick_exit_lockptr = lock; #endif void __funcs_on_quick_exit() { void (*func)(void); - LOCK(lock); + WEAK_LOCK(lock); while (count > 0) { func = funcs[--count]; - UNLOCK(lock); + WEAK_UNLOCK(lock); func(); - LOCK(lock); + WEAK_LOCK(lock); } } int at_quick_exit(void (*func)(void)) { int r = 0; - LOCK(lock); + WEAK_LOCK(lock); if (count == 32) r = -1; else funcs[count++] = func; - UNLOCK(lock); + WEAK_UNLOCK(lock); return r; } diff --git a/libc-top-half/musl/src/exit/atexit.c b/libc-top-half/musl/src/exit/atexit.c index 155292d0e..d52ae8267 100644 --- a/libc-top-half/musl/src/exit/atexit.c +++ b/libc-top-half/musl/src/exit/atexit.c @@ -22,20 +22,24 @@ static struct fl static int slot; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -static volatile int lock[1]; -volatile int *const __atexit_lockptr = lock; +#include "lock.h" + +// All locks here can be weak, because the locking is only needed to protect against +// concurrent manipulation of the handler table, which hits no context switch points. +__lock_t lock[1]; +__lock_t *const __atexit_lockptr = lock; #endif void __funcs_on_exit() { void (*func)(void *), *arg; - LOCK(lock); + WEAK_LOCK(lock); for (; head; head=head->next, slot=COUNT) while(slot-->0) { func = head->f[slot]; arg = head->a[slot]; - UNLOCK(lock); + WEAK_UNLOCK(lock); func(arg); - LOCK(lock); + WEAK_LOCK(lock); } } @@ -45,7 +49,7 @@ void __cxa_finalize(void *dso) int __cxa_atexit(void (*func)(void *), void *arg, void *dso) { - LOCK(lock); + WEAK_LOCK(lock); /* Defer initialization of head so it can be in BSS */ if (!head) head = &builtin; @@ -54,7 +58,7 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso) if (slot==COUNT) { struct fl *new_fl = calloc(sizeof(struct fl), 1); if (!new_fl) { - UNLOCK(lock); + WEAK_UNLOCK(lock); return -1; } new_fl->next = head; @@ -67,7 +71,7 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso) head->a[slot] = arg; slot++; - UNLOCK(lock); + WEAK_UNLOCK(lock); return 0; } diff --git a/libc-top-half/musl/src/internal/locale_impl.h b/libc-top-half/musl/src/internal/locale_impl.h index 88f5dcf8f..b792f8d0e 100644 --- a/libc-top-half/musl/src/internal/locale_impl.h +++ b/libc-top-half/musl/src/internal/locale_impl.h @@ -18,7 +18,8 @@ struct __locale_map { }; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -extern hidden volatile int __locale_lock[1]; +#include "lock.h" +extern hidden __lock_t __locale_lock[1]; #endif extern hidden const struct __locale_map __c_dot_utf8; diff --git a/libc-top-half/musl/src/internal/lock.h b/libc-top-half/musl/src/internal/lock.h index 29787fb1f..3e5a0a603 100644 --- a/libc-top-half/musl/src/internal/lock.h +++ b/libc-top-half/musl/src/internal/lock.h @@ -1,15 +1,50 @@ #ifndef LOCK_H #define LOCK_H -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +// Defines internal locking primitives. The main elements defined here are: +// - __lock_t: the type of a lock variable +// - __lock_ptr_t: the type of a pointer to a lock variable +// - __LOCK_INIT: initializer for a lock variable +// - STRONG_LOCK/STRONG_UNLOCK: functions to acquire/release a lock for a critical section that contains +// potential context switch points, and thus must be executed even in cooperative threading mode. +// - WEAK_LOCK/WEAK_UNLOCK: functions to acquire/release a lock for a critical section that does not contain any context switch points, +// and thus can be no-ops in cooperative threading mode. + + +#ifdef __wasi_cooperative_threads__ +struct __waitlist_node; +struct __coop_lock { + int owner; // tid of owning thread, or 0 if unlocked + struct __waitlist_node *waiters; +}; + +typedef struct __coop_lock __lock_t; +typedef struct __coop_lock *__lock_ptr_t; +#define __COOP_LOCK_INIT {0, NULL} +#define __LOCK_INIT __COOP_LOCK_INIT + +hidden void __lock(struct __coop_lock *lock); +hidden void __unlock(struct __coop_lock *lock); +#define STRONG_LOCK(x) __lock(x) +#define STRONG_UNLOCK(x) __unlock(x) +#define WEAK_LOCK(x) ((void)0) +#define WEAK_UNLOCK(x) ((void)0) +#elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +typedef volatile int __lock_t; +typedef volatile int *__lock_ptr_t; +#define __LOCK_INIT {0} hidden void __lock(volatile int *); hidden void __unlock(volatile int *); -#define LOCK(x) __lock(x) -#define UNLOCK(x) __unlock(x) +#define STRONG_LOCK(x) __lock(x) +#define STRONG_UNLOCK(x) __unlock(x) +#define WEAK_LOCK(x) __lock(x) +#define WEAK_UNLOCK(x) __unlock(x) #else // No locking needed. -#define LOCK(x) ((void)0) -#define UNLOCK(x) ((void)0) +#define STRONG_LOCK(x) ((void)0) +#define STRONG_UNLOCK(x) ((void)0) +#define WEAK_LOCK(x) ((void)0) +#define WEAK_UNLOCK(x) ((void)0) #endif -#endif +#endif \ No newline at end of file diff --git a/libc-top-half/musl/src/internal/pthread_impl.h b/libc-top-half/musl/src/internal/pthread_impl.h index 0106ac385..7a056d69d 100644 --- a/libc-top-half/musl/src/internal/pthread_impl.h +++ b/libc-top-half/musl/src/internal/pthread_impl.h @@ -18,6 +18,8 @@ #include "futex.h" #include "pthread_arch.h" +#include "lock.h" +#include #define pthread __pthread @@ -172,35 +174,24 @@ hidden int __libc_sigaction(int, const struct sigaction *, struct sigaction *); #endif hidden void __unmapself(void *, size_t); +#ifdef __wasi_cooperative_threads__ +struct __waitlist_node { + uint32_t tid; + struct __waitlist_node *next; +}; +hidden void __waitlist_wait_on(struct __waitlist_node **list); +hidden void __waitlist_wake_one(struct __waitlist_node **list); +hidden void __waitlist_wake_all(struct __waitlist_node **list); +#else #ifndef __wasilibc_unmodified_upstream hidden int __wasilibc_futex_wait(volatile void *, int, int, int64_t); #endif hidden int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int); hidden int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int); hidden void __wait(volatile int *, volatile int *, int, int); -static inline void __wake(volatile void *addr, int cnt, int priv) -{ - if (priv) priv = FUTEX_PRIVATE; - if (cnt<0) cnt = INT_MAX; -#ifdef __wasilibc_unmodified_upstream - __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || - __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); -#else -#ifdef _REENTRANT - __builtin_wasm_memory_atomic_notify((int*)addr, cnt); -#endif -#endif -} -static inline void __futexwait(volatile void *addr, int val, int priv) -{ -#ifdef __wasilibc_unmodified_upstream - if (priv) priv = FUTEX_PRIVATE; - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || - __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); -#else - __wait(addr, NULL, val, priv); +hidden void __wake(volatile void *addr, int cnt, int priv); +hidden void __futexwait(volatile void *addr, int val, int priv); #endif -} hidden void __acquire_ptc(void); hidden void __release_ptc(void); diff --git a/libc-top-half/musl/src/internal/stdio_impl.h b/libc-top-half/musl/src/internal/stdio_impl.h index 7f19dd951..ce0e1bc2f 100644 --- a/libc-top-half/musl/src/internal/stdio_impl.h +++ b/libc-top-half/musl/src/internal/stdio_impl.h @@ -8,10 +8,20 @@ #define UNGET 8 -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#include "lock.h" + +#ifdef __wasi_cooperative_threads__ +#define FFINALLOCK(f) __lockfile((f)) +#define FLOCK(f) int __need_unlock = __lockfile((f)) +#define FUNLOCK(f) do { if (__need_unlock) __unlockfile((f)); } while (0) +#define __STDIO_LOCK_INIT {0, 0} +#define __STDIO_LOCK_RESET(lock) do { (lock)->owner = 0; (lock)->waiters = NULL; } while (0) +#elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0) #define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0) #define FUNLOCK(f) do { if (__need_unlock) __unlockfile((f)); } while (0) +#define __STDIO_LOCK_INIT -1 +#define __STDIO_LOCK_RESET(lock) do { (*(lock)) = -1; } while (0) #else // No locking needed. #define FFINALLOCK(f) ((void)(f)) @@ -51,7 +61,7 @@ struct _IO_FILE { #endif int mode; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - volatile int lock; + __lock_t lock; #endif int lbf; void *cookie; diff --git a/libc-top-half/musl/src/locale/locale_map.c b/libc-top-half/musl/src/locale/locale_map.c index ebfb158f4..ca25ac827 100644 --- a/libc-top-half/musl/src/locale/locale_map.c +++ b/libc-top-half/musl/src/locale/locale_map.c @@ -31,8 +31,8 @@ static const char envvars[][12] = { }; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -volatile int __locale_lock[1]; -volatile int *const __locale_lockptr = __locale_lock; +__lock_t __locale_lock[1]; +__lock_t *const __locale_lockptr = __locale_lock; #endif const struct __locale_map *__get_locale(int cat, const char *val) diff --git a/libc-top-half/musl/src/locale/newlocale.c b/libc-top-half/musl/src/locale/newlocale.c index 11c778557..814adab0e 100644 --- a/libc-top-half/musl/src/locale/newlocale.c +++ b/libc-top-half/musl/src/locale/newlocale.c @@ -63,9 +63,9 @@ static locale_t do_newlocale(int mask, const char *name, locale_t loc) locale_t __newlocale(int mask, const char *name, locale_t loc) { - LOCK(__locale_lock); + STRONG_LOCK(__locale_lock); loc = do_newlocale(mask, name, loc); - UNLOCK(__locale_lock); + STRONG_UNLOCK(__locale_lock); return loc; } diff --git a/libc-top-half/musl/src/locale/setlocale.c b/libc-top-half/musl/src/locale/setlocale.c index 360c44376..18f2a2c1e 100644 --- a/libc-top-half/musl/src/locale/setlocale.c +++ b/libc-top-half/musl/src/locale/setlocale.c @@ -13,7 +13,7 @@ char *setlocale(int cat, const char *name) if ((unsigned)cat > LC_ALL) return 0; - LOCK(__locale_lock); + STRONG_LOCK(__locale_lock); /* For LC_ALL, setlocale is required to return a string which * encodes the current setting for all categories. The format of @@ -35,7 +35,7 @@ char *setlocale(int cat, const char *name) } lm = __get_locale(i, part); if (lm == LOC_MAP_FAILED) { - UNLOCK(__locale_lock); + STRONG_UNLOCK(__locale_lock); return 0; } tmp_locale.cat[i] = lm; @@ -56,14 +56,14 @@ char *setlocale(int cat, const char *name) s += l+1; } *--s = 0; - UNLOCK(__locale_lock); + STRONG_UNLOCK(__locale_lock); return same==LC_ALL ? (char *)part : buf; } if (name) { lm = __get_locale(cat, name); if (lm == LOC_MAP_FAILED) { - UNLOCK(__locale_lock); + STRONG_UNLOCK(__locale_lock); return 0; } libc.global_locale.cat[cat] = lm; @@ -72,7 +72,7 @@ char *setlocale(int cat, const char *name) } char *ret = lm ? (char *)lm->name : "C"; - UNLOCK(__locale_lock); + STRONG_UNLOCK(__locale_lock); return ret; } diff --git a/libc-top-half/musl/src/malloc/oldmalloc/malloc.c b/libc-top-half/musl/src/malloc/oldmalloc/malloc.c index 25d00d44d..f4caed87c 100644 --- a/libc-top-half/musl/src/malloc/oldmalloc/malloc.c +++ b/libc-top-half/musl/src/malloc/oldmalloc/malloc.c @@ -27,6 +27,16 @@ static struct { /* Synchronization tools */ +#ifdef __wasi_cooperative_threads__ +/* The implementation has no yield points, so locks can be no-ops. */ +static inline void lock(volatile int *lk) +{ +} + +static inline void unlock(volatile int *lk) +{ +} +#else static inline void lock(volatile int *lk) { int need_locks = libc.need_locks; @@ -43,6 +53,7 @@ static inline void unlock(volatile int *lk) if (lk[1]) __wake(lk, 1, 1); } } +#endif static inline void lock_bin(int i) { diff --git a/libc-top-half/musl/src/prng/random.c b/libc-top-half/musl/src/prng/random.c index daac028d8..957f2f955 100644 --- a/libc-top-half/musl/src/prng/random.c +++ b/libc-top-half/musl/src/prng/random.c @@ -24,8 +24,8 @@ static int i = 3; static int j = 0; static uint32_t *x = init+1; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -static volatile int lock[1]; -volatile int *const __random_lockptr = lock; +static __lock_t lock[1]; +__lock_t *const __random_lockptr = lock; #endif static uint32_t lcg31(uint32_t x) { @@ -67,9 +67,11 @@ static void __srandom(unsigned seed) { } void srandom(unsigned seed) { - LOCK(lock); + // The random number generator does not hit any context switch points, + // so we can use weak locks here. + WEAK_LOCK(lock); __srandom(seed); - UNLOCK(lock); + WEAK_UNLOCK(lock); } char *initstate(unsigned seed, char *state, size_t size) { @@ -77,7 +79,7 @@ char *initstate(unsigned seed, char *state, size_t size) { if (size < 8) return 0; - LOCK(lock); + WEAK_LOCK(lock); old = savestate(); if (size < 32) n = 0; @@ -92,24 +94,24 @@ char *initstate(unsigned seed, char *state, size_t size) { x = (uint32_t*)state + 1; __srandom(seed); savestate(); - UNLOCK(lock); + WEAK_UNLOCK(lock); return old; } char *setstate(char *state) { void *old; - LOCK(lock); + WEAK_LOCK(lock); old = savestate(); loadstate((uint32_t*)state); - UNLOCK(lock); + WEAK_UNLOCK(lock); return old; } long random(void) { long k; - LOCK(lock); + WEAK_LOCK(lock); if (n == 0) { k = x[0] = lcg31(x[0]); goto end; @@ -121,6 +123,6 @@ long random(void) { if (++j == n) j = 0; end: - UNLOCK(lock); + WEAK_UNLOCK(lock); return k; } diff --git a/libc-top-half/musl/src/stdio/__fdopen.c b/libc-top-half/musl/src/stdio/__fdopen.c index 5c8df495e..205338c2f 100644 --- a/libc-top-half/musl/src/stdio/__fdopen.c +++ b/libc-top-half/musl/src/stdio/__fdopen.c @@ -75,7 +75,7 @@ FILE *__fdopen(int fd, const char *mode) f->close = __stdio_close; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - if (!libc.threaded) f->lock = -1; + if (!libc.threaded) __STDIO_LOCK_RESET(&f->lock); #endif /* Add new FILE to open file list */ diff --git a/libc-top-half/musl/src/stdio/__fopen_rb_ca.c b/libc-top-half/musl/src/stdio/__fopen_rb_ca.c index 192050b00..27c2544fe 100644 --- a/libc-top-half/musl/src/stdio/__fopen_rb_ca.c +++ b/libc-top-half/musl/src/stdio/__fopen_rb_ca.c @@ -25,7 +25,7 @@ FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t le f->seek = __stdio_seek; f->close = __stdio_close; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - f->lock = -1; + __STDIO_LOCK_RESET(&f->lock); #endif return f; diff --git a/libc-top-half/musl/src/stdio/__lockfile.c b/libc-top-half/musl/src/stdio/__lockfile.c index 0f60a1499..206e46597 100644 --- a/libc-top-half/musl/src/stdio/__lockfile.c +++ b/libc-top-half/musl/src/stdio/__lockfile.c @@ -1,6 +1,29 @@ #include "stdio_impl.h" #include "pthread_impl.h" +#ifdef __wasi_cooperative_threads__ +#include "lock.h" +int __lockfile(FILE *f) +{ + #ifdef __wasip3__ + int tid = wasip3_thread_index(); + #else + #error "Unknown WASI version" + #endif + + // Allow recursive locking + if (f->lock.owner == tid) + return 0; + + STRONG_LOCK(&f->lock); + return 1; +} + +void __unlockfile(FILE *f) +{ + STRONG_UNLOCK(&f->lock); +} +#else int __lockfile(FILE *f) { int owner = f->lock, tid = __pthread_self()->tid; @@ -21,3 +44,4 @@ void __unlockfile(FILE *f) if (a_swap(&f->lock, 0) & MAYBE_WAITERS) __wake(&f->lock, 1, 1); } +#endif diff --git a/libc-top-half/musl/src/stdio/fmemopen.c b/libc-top-half/musl/src/stdio/fmemopen.c index 3ee57b9ea..22628e56f 100644 --- a/libc-top-half/musl/src/stdio/fmemopen.c +++ b/libc-top-half/musl/src/stdio/fmemopen.c @@ -130,7 +130,7 @@ FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) f->f.close = mclose; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - if (!libc.threaded) f->f.lock = -1; + if (!libc.threaded) __STDIO_LOCK_RESET(&f->f.lock); #endif return __ofl_add(&f->f); diff --git a/libc-top-half/musl/src/stdio/ftrylockfile.c b/libc-top-half/musl/src/stdio/ftrylockfile.c index 50650585b..931214ffa 100644 --- a/libc-top-half/musl/src/stdio/ftrylockfile.c +++ b/libc-top-half/musl/src/stdio/ftrylockfile.c @@ -4,9 +4,15 @@ void __do_orphaned_stdio_locks() { - FILE *f; - for (f=__pthread_self()->stdio_locks; f; f=f->next_locked) - a_store(&f->lock, 0x40000000); + FILE *f; + for (f=__pthread_self()->stdio_locks; f; f=f->next_locked) { + #ifdef __wasi_cooperative_threads__ + f->lock.owner = 0; + __waitlist_wake_all(&f->lock.waiters); + #else + a_store(&f->lock, 0x40000000); + #endif + } } void __unlist_locked_file(FILE *f) @@ -27,6 +33,31 @@ void __register_locked_file(FILE *f, pthread_t self) self->stdio_locks = f; } +#ifdef __wasi_cooperative_threads__ +int ftrylockfile(FILE *f) +{ + #ifdef __wasip3__ + uint32_t self_tid = wasip3_thread_index(); + #else + #error "Unknown WASI version" + #endif + + if (f->lock.owner == self_tid) { + if (f->lockcount == LONG_MAX) + return -1; + f->lockcount++; + return 0; + } + + // Try to acquire the lock + if (f->lock.owner != 0) + return -1; + + f->lock.owner = self_tid; + f->lockcount = 1; + return 0; +} +#else int ftrylockfile(FILE *f) { pthread_t self = __pthread_self(); @@ -44,3 +75,4 @@ int ftrylockfile(FILE *f) __register_locked_file(f, self); return 0; } +#endif diff --git a/libc-top-half/musl/src/stdio/getc.h b/libc-top-half/musl/src/stdio/getc.h index e62e3f0da..7502102dc 100644 --- a/libc-top-half/musl/src/stdio/getc.h +++ b/libc-top-half/musl/src/stdio/getc.h @@ -7,17 +7,28 @@ __attribute__((__noinline__)) #endif static int locking_getc(FILE *f) { +#ifdef __wasi_cooperative_threads__ + __lockfile(f); + int c = getc_unlocked(f); + __unlockfile(f); + return c; +#else if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f); int c = getc_unlocked(f); if (a_swap(&f->lock, 0) & MAYBE_WAITERS) __wake(&f->lock, 1, 1); return c; +#endif } #endif static inline int do_getc(FILE *f) { -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#ifdef __wasi_cooperative_threads__ + if (f->lock.owner == wasip3_thread_index()) + return getc_unlocked(f); + return locking_getc(f); +#elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) int l = f->lock; if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid) return getc_unlocked(f); diff --git a/libc-top-half/musl/src/stdio/ofl.c b/libc-top-half/musl/src/stdio/ofl.c index 33a8aa50b..2a298a2f8 100644 --- a/libc-top-half/musl/src/stdio/ofl.c +++ b/libc-top-half/musl/src/stdio/ofl.c @@ -4,17 +4,17 @@ static FILE *ofl_head; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -static volatile int ofl_lock[1]; -volatile int *const __stdio_ofl_lockptr = ofl_lock; +static __lock_t ofl_lock[1]; +__lock_t *const __stdio_ofl_lockptr = ofl_lock; #endif FILE **__ofl_lock() { - LOCK(ofl_lock); + STRONG_LOCK(ofl_lock); return &ofl_head; } void __ofl_unlock() { - UNLOCK(ofl_lock); + STRONG_UNLOCK(ofl_lock); } diff --git a/libc-top-half/musl/src/stdio/open_memstream.c b/libc-top-half/musl/src/stdio/open_memstream.c index aa5022065..9690fe8b3 100644 --- a/libc-top-half/musl/src/stdio/open_memstream.c +++ b/libc-top-half/musl/src/stdio/open_memstream.c @@ -102,7 +102,7 @@ FILE *open_memstream(char **bufp, size_t *sizep) f->f.mode = -1; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - if (!libc.threaded) f->f.lock = -1; + if (!libc.threaded) __STDIO_LOCK_RESET(&f->f.lock); #endif return __ofl_add(&f->f); diff --git a/libc-top-half/musl/src/stdio/open_wmemstream.c b/libc-top-half/musl/src/stdio/open_wmemstream.c index 198d5d439..d06c24db8 100644 --- a/libc-top-half/musl/src/stdio/open_wmemstream.c +++ b/libc-top-half/musl/src/stdio/open_wmemstream.c @@ -107,7 +107,7 @@ FILE *open_wmemstream(wchar_t **bufp, size_t *sizep) f->f.close = wms_close; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - if (!libc.threaded) f->f.lock = -1; + if (!libc.threaded) __STDIO_LOCK_RESET(&f->f.lock); #endif fwide(&f->f, 1); diff --git a/libc-top-half/musl/src/stdio/putc.h b/libc-top-half/musl/src/stdio/putc.h index 2cc63d2db..aae780ab3 100644 --- a/libc-top-half/musl/src/stdio/putc.h +++ b/libc-top-half/musl/src/stdio/putc.h @@ -7,17 +7,33 @@ __attribute__((__noinline__)) #endif static int locking_putc(int c, FILE *f) { +#ifdef __wasi_cooperative_threads__ + __lockfile(f); + c = putc_unlocked(c, f); + __unlockfile(f); + return c; +#else if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f); c = putc_unlocked(c, f); if (a_swap(&f->lock, 0) & MAYBE_WAITERS) __wake(&f->lock, 1, 1); return c; +#endif } #endif static inline int do_putc(int c, FILE *f) { -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#ifdef __wasi_cooperative_threads__ + #ifdef __wasip3__ + int tid = wasip3_thread_index(); + #else + #error "Unknown WASI version" + #endif + if (f->lock.owner == tid) + return putc_unlocked(c, f); + return locking_putc(c, f); +#elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) int l = f->lock; if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid) return putc_unlocked(c, f); diff --git a/libc-top-half/musl/src/stdio/stderr.c b/libc-top-half/musl/src/stdio/stderr.c index 5f24549f8..a14ba5637 100644 --- a/libc-top-half/musl/src/stdio/stderr.c +++ b/libc-top-half/musl/src/stdio/stderr.c @@ -13,7 +13,7 @@ hidden FILE __stderr_FILE = { .seek = __stdio_seek, .close = __stdio_close, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .lock = -1, + .lock = __STDIO_LOCK_INIT, #endif }; FILE *const stderr = &__stderr_FILE; diff --git a/libc-top-half/musl/src/stdio/stdin.c b/libc-top-half/musl/src/stdio/stdin.c index 68e1c3f64..ddc1a892a 100644 --- a/libc-top-half/musl/src/stdio/stdin.c +++ b/libc-top-half/musl/src/stdio/stdin.c @@ -12,7 +12,7 @@ hidden FILE __stdin_FILE = { .seek = __stdio_seek, .close = __stdio_close, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .lock = -1, + .lock = __STDIO_LOCK_INIT, #endif }; FILE *const stdin = &__stdin_FILE; diff --git a/libc-top-half/musl/src/stdio/stdout.c b/libc-top-half/musl/src/stdio/stdout.c index e0e2bced9..914f5a456 100644 --- a/libc-top-half/musl/src/stdio/stdout.c +++ b/libc-top-half/musl/src/stdio/stdout.c @@ -13,7 +13,7 @@ hidden FILE __stdout_FILE = { .seek = __stdio_seek, .close = __stdio_close, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .lock = -1, + .lock = __STDIO_LOCK_INIT, #endif }; FILE *const stdout = &__stdout_FILE; diff --git a/libc-top-half/musl/src/stdio/vdprintf.c b/libc-top-half/musl/src/stdio/vdprintf.c index cef0a1af2..4ab32308a 100644 --- a/libc-top-half/musl/src/stdio/vdprintf.c +++ b/libc-top-half/musl/src/stdio/vdprintf.c @@ -6,7 +6,7 @@ int vdprintf(int fd, const char *restrict fmt, va_list ap) .fd = fd, .lbf = EOF, .write = __stdio_write, .buf = (void *)fmt, .buf_size = 0, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .lock = -1 + .lock = __STDIO_LOCK_INIT, #endif }; return vfprintf(&f, fmt, ap); diff --git a/libc-top-half/musl/src/stdio/vsscanf.c b/libc-top-half/musl/src/stdio/vsscanf.c index 0e5b48265..883e1d8c4 100644 --- a/libc-top-half/musl/src/stdio/vsscanf.c +++ b/libc-top-half/musl/src/stdio/vsscanf.c @@ -19,10 +19,9 @@ int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap) { FILE f = { .buf = (void *)s, .cookie = (void *)s, + .read = string_read, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .read = string_read, .lock = -1 -#else - .read = string_read + .lock = __STDIO_LOCK_INIT #endif }; return vfscanf(&f, fmt, ap); diff --git a/libc-top-half/musl/src/stdio/vswscanf.c b/libc-top-half/musl/src/stdio/vswscanf.c index ea827102d..feef4e451 100644 --- a/libc-top-half/musl/src/stdio/vswscanf.c +++ b/libc-top-half/musl/src/stdio/vswscanf.c @@ -30,10 +30,9 @@ int vswscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, va_list ap) FILE f = { .buf = buf, .buf_size = sizeof buf, .cookie = (void *)s, + .read = wstring_read, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .read = wstring_read, .lock = -1 -#else - .read = wstring_read + .lock = __STDIO_LOCK_INIT #endif }; return vfwscanf(&f, fmt, ap); diff --git a/libc-top-half/musl/src/stdlib/wcstod.c b/libc-top-half/musl/src/stdlib/wcstod.c index 97b894eb2..c198f08c5 100644 --- a/libc-top-half/musl/src/stdlib/wcstod.c +++ b/libc-top-half/musl/src/stdlib/wcstod.c @@ -44,7 +44,7 @@ static long double wcstox(const wchar_t *s, wchar_t **p, int prec) f.rpos = f.rend = f.buf = buf + 4; f.buf_size = sizeof buf - 4; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - f.lock = -1; + __STDIO_LOCK_RESET(&f.lock); #endif f.read = do_read; while (iswspace(*t)) t++; diff --git a/libc-top-half/musl/src/stdlib/wcstol.c b/libc-top-half/musl/src/stdlib/wcstol.c index 3aefd06f4..43439c0d0 100644 --- a/libc-top-half/musl/src/stdlib/wcstol.c +++ b/libc-top-half/musl/src/stdlib/wcstol.c @@ -38,7 +38,7 @@ static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsign f.rpos = f.rend = f.buf = buf + 4; f.buf_size = sizeof buf - 4; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - f.lock = -1; + __STDIO_LOCK_RESET(&f.lock); #endif f.read = do_read; while (iswspace(*t)) t++; diff --git a/libc-top-half/musl/src/thread/coop-threads/__lock.c b/libc-top-half/musl/src/thread/coop-threads/__lock.c new file mode 100644 index 000000000..9baeceff0 --- /dev/null +++ b/libc-top-half/musl/src/thread/coop-threads/__lock.c @@ -0,0 +1,38 @@ +#include "pthread_impl.h" +#include "lock.h" +#include + +#ifndef __wasip3__ +#error "Unknown WASI version" +#endif + +void __lock(struct __coop_lock *lock) +{ + int tid = wasip3_thread_index(); + if (lock->owner == tid) { + /* Trap on recursive locking. */ + __builtin_trap(); + } + + /* Loop until we acquire the lock. */ + while (lock->owner != 0) { + __waitlist_wait_on(&lock->waiters); + /* After waking, the lock might still be held by another + * thread that was scheduled before us, so loop back. */ + } + + lock->owner = tid; +} + +void __unlock(struct __coop_lock *lock) +{ + int tid = wasip3_thread_index(); + if (lock->owner != tid) { + /* We're trying to unlock a lock we don't own. */ + __builtin_trap(); + } + + lock->owner = 0; + /* Awake one waiter; the others will be resumed on future unlocks. */ + __waitlist_wake_one(&lock->waiters); +} \ No newline at end of file diff --git a/libc-top-half/musl/src/thread/coop-threads/__wait.c b/libc-top-half/musl/src/thread/coop-threads/__wait.c new file mode 100644 index 000000000..1ccae74a5 --- /dev/null +++ b/libc-top-half/musl/src/thread/coop-threads/__wait.c @@ -0,0 +1,47 @@ +#include "pthread_impl.h" +#include + +#ifndef __wasip3__ +#error "Unknown WASI version" +#endif + +void __waitlist_wait_on(struct __waitlist_node **list) +{ + struct __waitlist_node node = { + .tid = wasip3_thread_index(), + .next = *list, + }; + *list = &node; + + wasip3_thread_suspend(); +} + +void __waitlist_wake_one(struct __waitlist_node **list) +{ + if (*list == NULL) { + return; + } + struct __waitlist_node *node = *list; + *list = node->next; + wasip3_thread_yield_to_suspended(node->tid); +} + +void __waitlist_wake_all(struct __waitlist_node **list) +{ + struct __waitlist_node **prev = list; + struct __waitlist_node *curr = *list; + + while (curr) { + uint32_t tid = curr->tid; + *prev = curr->next; + // As a scheduling optimization, we always yield directly to the last + // suspended thread instead of just scheduling it to run at some point. + if (curr->next == NULL) { + wasip3_thread_yield_to_suspended(tid); + } + else { + wasip3_thread_unsuspend(tid); + } + curr = *prev; + } +} \ No newline at end of file From 36a0eed691a1a0ad4848221d37b55f7d614be41b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 19:27:23 +0000 Subject: [PATCH 05/28] Cleanup --- CMakeLists.txt | 3 +++ .../cloudlibc/src/libc/sched/sched_yield.c | 1 - libc-top-half/CMakeLists.txt | 9 +++++++++ libc-top-half/musl/src/env/__init_tls.c | 10 +++++++++- libc-top-half/musl/src/internal/lock.h | 2 ++ libc-top-half/musl/src/internal/stdio_impl.h | 1 + libc-top-half/musl/src/stdio/__lockfile.c | 8 +------- libc-top-half/musl/src/stdio/ftrylockfile.c | 7 +------ libc-top-half/musl/src/stdio/getc.h | 3 ++- libc-top-half/musl/src/stdio/putc.h | 8 ++------ libc-top-half/musl/src/thread/coop-threads/__lock.c | 7 +++---- libc-top-half/musl/src/thread/coop-threads/__wait.c | 2 +- 12 files changed, 34 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86793fdc8..5e261d183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,9 @@ endif() if(TARGET_TRIPLE MATCHES "-threads$") set(THREADS ON) add_compile_options(-mthread-model posix -pthread -ftls-model=local-exec -matomics) +elseif(TARGET_TRIPLE MATCHES "-wasip3$") + set(THREADS OFF) + add_compile_options(-mthread-model posix -pthread -ftls-model=local-exec) else() set(THREADS OFF) add_compile_options(-mthread-model single) diff --git a/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c b/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c index c4b298e33..ceb0c9d43 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c +++ b/libc-bottom-half/cloudlibc/src/libc/sched/sched_yield.c @@ -15,7 +15,6 @@ int sched_yield(void) { #error "Unknown WASI version" #endif #elif defined(__wasip1__) -#ifdef __wasip1__ __wasi_errno_t error = __wasi_sched_yield(); if (error != 0) { errno = error; diff --git a/libc-top-half/CMakeLists.txt b/libc-top-half/CMakeLists.txt index 69f758eb6..4777ba5d6 100644 --- a/libc-top-half/CMakeLists.txt +++ b/libc-top-half/CMakeLists.txt @@ -473,6 +473,15 @@ else() ) endif() +# Cooperative threading lock/waiting primitives +if (WASI STREQUAL "p3") + list(APPEND top_half_sources + musl/src/stdio/__lockfile.c + musl/src/thread/coop-threads/__lock.c + musl/src/thread/coop-threads/__wait.c + ) +endif() + add_object_library(top-half ${top_half_sources}) foreach(obj top-half-shared top-half-static) target_link_libraries(${obj} PUBLIC musl-top-half-interface) diff --git a/libc-top-half/musl/src/env/__init_tls.c b/libc-top-half/musl/src/env/__init_tls.c index 7f0d92931..c37507749 100644 --- a/libc-top-half/musl/src/env/__init_tls.c +++ b/libc-top-half/musl/src/env/__init_tls.c @@ -12,6 +12,7 @@ #include "libc.h" #include "atomic.h" #include "syscall.h" +#include #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) volatile int __thread_list_lock; @@ -97,7 +98,14 @@ int __init_tp(void *p) td->stack = bounds.base; td->stack_size = bounds.size; td->guard_size = 0; -#ifdef _REENTRANT +#ifdef __wasi_cooperative_threads__ + td->detach_state = DT_JOINABLE; + #ifdef __wasip3__ + td->tid = wasip3_thread_index(); + #else + #error "Unknown WASI version" + #endif +#elif defined(_REENTRANT) td->detach_state = DT_JOINABLE; /* * Initialize the TID to a value which doesn't conflict with diff --git a/libc-top-half/musl/src/internal/lock.h b/libc-top-half/musl/src/internal/lock.h index 3e5a0a603..34503a002 100644 --- a/libc-top-half/musl/src/internal/lock.h +++ b/libc-top-half/musl/src/internal/lock.h @@ -1,6 +1,8 @@ #ifndef LOCK_H #define LOCK_H +#include + // Defines internal locking primitives. The main elements defined here are: // - __lock_t: the type of a lock variable // - __lock_ptr_t: the type of a pointer to a lock variable diff --git a/libc-top-half/musl/src/internal/stdio_impl.h b/libc-top-half/musl/src/internal/stdio_impl.h index ce0e1bc2f..7ea811393 100644 --- a/libc-top-half/musl/src/internal/stdio_impl.h +++ b/libc-top-half/musl/src/internal/stdio_impl.h @@ -9,6 +9,7 @@ #define UNGET 8 #include "lock.h" +#include #ifdef __wasi_cooperative_threads__ #define FFINALLOCK(f) __lockfile((f)) diff --git a/libc-top-half/musl/src/stdio/__lockfile.c b/libc-top-half/musl/src/stdio/__lockfile.c index 206e46597..042742547 100644 --- a/libc-top-half/musl/src/stdio/__lockfile.c +++ b/libc-top-half/musl/src/stdio/__lockfile.c @@ -5,14 +5,8 @@ #include "lock.h" int __lockfile(FILE *f) { - #ifdef __wasip3__ - int tid = wasip3_thread_index(); - #else - #error "Unknown WASI version" - #endif - // Allow recursive locking - if (f->lock.owner == tid) + if (f->lock.owner == __pthread_self()->tid) return 0; STRONG_LOCK(&f->lock); diff --git a/libc-top-half/musl/src/stdio/ftrylockfile.c b/libc-top-half/musl/src/stdio/ftrylockfile.c index 931214ffa..489d46f88 100644 --- a/libc-top-half/musl/src/stdio/ftrylockfile.c +++ b/libc-top-half/musl/src/stdio/ftrylockfile.c @@ -36,12 +36,7 @@ void __register_locked_file(FILE *f, pthread_t self) #ifdef __wasi_cooperative_threads__ int ftrylockfile(FILE *f) { - #ifdef __wasip3__ - uint32_t self_tid = wasip3_thread_index(); - #else - #error "Unknown WASI version" - #endif - + int self_tid = __pthread_self()->tid; if (f->lock.owner == self_tid) { if (f->lockcount == LONG_MAX) return -1; diff --git a/libc-top-half/musl/src/stdio/getc.h b/libc-top-half/musl/src/stdio/getc.h index 7502102dc..61074d607 100644 --- a/libc-top-half/musl/src/stdio/getc.h +++ b/libc-top-half/musl/src/stdio/getc.h @@ -1,6 +1,7 @@ #include "stdio_impl.h" #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #include "pthread_impl.h" +#include #ifdef __GNUC__ __attribute__((__noinline__)) @@ -25,7 +26,7 @@ static int locking_getc(FILE *f) static inline int do_getc(FILE *f) { #ifdef __wasi_cooperative_threads__ - if (f->lock.owner == wasip3_thread_index()) + if (f->lock.owner == __pthread_self()->tid) return getc_unlocked(f); return locking_getc(f); #elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) diff --git a/libc-top-half/musl/src/stdio/putc.h b/libc-top-half/musl/src/stdio/putc.h index aae780ab3..7e1d49d6b 100644 --- a/libc-top-half/musl/src/stdio/putc.h +++ b/libc-top-half/musl/src/stdio/putc.h @@ -1,6 +1,7 @@ #include "stdio_impl.h" #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #include "pthread_impl.h" +#include #ifdef __GNUC__ __attribute__((__noinline__)) @@ -25,12 +26,7 @@ static int locking_putc(int c, FILE *f) static inline int do_putc(int c, FILE *f) { #ifdef __wasi_cooperative_threads__ - #ifdef __wasip3__ - int tid = wasip3_thread_index(); - #else - #error "Unknown WASI version" - #endif - if (f->lock.owner == tid) + if (f->lock.owner == __pthread_self()->tid) return putc_unlocked(c, f); return locking_putc(c, f); #elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) diff --git a/libc-top-half/musl/src/thread/coop-threads/__lock.c b/libc-top-half/musl/src/thread/coop-threads/__lock.c index 9baeceff0..939d87ad9 100644 --- a/libc-top-half/musl/src/thread/coop-threads/__lock.c +++ b/libc-top-half/musl/src/thread/coop-threads/__lock.c @@ -8,8 +8,7 @@ void __lock(struct __coop_lock *lock) { - int tid = wasip3_thread_index(); - if (lock->owner == tid) { + if (lock->owner == __pthread_self()->tid) { /* Trap on recursive locking. */ __builtin_trap(); } @@ -21,12 +20,12 @@ void __lock(struct __coop_lock *lock) * thread that was scheduled before us, so loop back. */ } - lock->owner = tid; + lock->owner = __pthread_self()->tid; } void __unlock(struct __coop_lock *lock) { - int tid = wasip3_thread_index(); + int tid = __pthread_self()->tid; if (lock->owner != tid) { /* We're trying to unlock a lock we don't own. */ __builtin_trap(); diff --git a/libc-top-half/musl/src/thread/coop-threads/__wait.c b/libc-top-half/musl/src/thread/coop-threads/__wait.c index 1ccae74a5..db8646dcc 100644 --- a/libc-top-half/musl/src/thread/coop-threads/__wait.c +++ b/libc-top-half/musl/src/thread/coop-threads/__wait.c @@ -8,7 +8,7 @@ void __waitlist_wait_on(struct __waitlist_node **list) { struct __waitlist_node node = { - .tid = wasip3_thread_index(), + .tid = __pthread_self()->tid, .next = *list, }; *list = &node; From 6e8568b5690e2cac90c100c2e17846dfd6ab434b Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 19:31:51 +0000 Subject: [PATCH 06/28] Formatting --- libc-top-half/musl/src/internal/lock.h | 64 ++++++++++++++------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/libc-top-half/musl/src/internal/lock.h b/libc-top-half/musl/src/internal/lock.h index 34503a002..75d405524 100644 --- a/libc-top-half/musl/src/internal/lock.h +++ b/libc-top-half/musl/src/internal/lock.h @@ -14,39 +14,43 @@ #ifdef __wasi_cooperative_threads__ -struct __waitlist_node; -struct __coop_lock { - int owner; // tid of owning thread, or 0 if unlocked - struct __waitlist_node *waiters; -}; + struct __waitlist_node; + struct __coop_lock { + int owner; // tid of owning thread, or 0 if unlocked + struct __waitlist_node *waiters; + }; + + typedef struct __coop_lock __lock_t; + typedef struct __coop_lock *__lock_ptr_t; + #define __COOP_LOCK_INIT {0, NULL} + #define __LOCK_INIT __COOP_LOCK_INIT + + hidden void __lock(struct __coop_lock *lock); + hidden void __unlock(struct __coop_lock *lock); -typedef struct __coop_lock __lock_t; -typedef struct __coop_lock *__lock_ptr_t; -#define __COOP_LOCK_INIT {0, NULL} -#define __LOCK_INIT __COOP_LOCK_INIT - -hidden void __lock(struct __coop_lock *lock); -hidden void __unlock(struct __coop_lock *lock); -#define STRONG_LOCK(x) __lock(x) -#define STRONG_UNLOCK(x) __unlock(x) -#define WEAK_LOCK(x) ((void)0) -#define WEAK_UNLOCK(x) ((void)0) + #define STRONG_LOCK(x) __lock(x) + #define STRONG_UNLOCK(x) __unlock(x) + #define WEAK_LOCK(x) ((void)0) + #define WEAK_UNLOCK(x) ((void)0) #elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -typedef volatile int __lock_t; -typedef volatile int *__lock_ptr_t; -#define __LOCK_INIT {0} -hidden void __lock(volatile int *); -hidden void __unlock(volatile int *); -#define STRONG_LOCK(x) __lock(x) -#define STRONG_UNLOCK(x) __unlock(x) -#define WEAK_LOCK(x) __lock(x) -#define WEAK_UNLOCK(x) __unlock(x) + typedef volatile int __lock_t; + typedef volatile int *__lock_ptr_t; + + #define __LOCK_INIT {0} + + hidden void __lock(volatile int *); + hidden void __unlock(volatile int *); + + #define STRONG_LOCK(x) __lock(x) + #define STRONG_UNLOCK(x) __unlock(x) + #define WEAK_LOCK(x) __lock(x) + #define WEAK_UNLOCK(x) __unlock(x) #else -// No locking needed. -#define STRONG_LOCK(x) ((void)0) -#define STRONG_UNLOCK(x) ((void)0) -#define WEAK_LOCK(x) ((void)0) -#define WEAK_UNLOCK(x) ((void)0) + // No locking needed. + #define STRONG_LOCK(x) ((void)0) + #define STRONG_UNLOCK(x) ((void)0) + #define WEAK_LOCK(x) ((void)0) + #define WEAK_UNLOCK(x) ((void)0) #endif #endif \ No newline at end of file From ac451090c2d404b3a2b6aed589cb090c8732977d Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:19:38 +0000 Subject: [PATCH 07/28] Rename STRONG_LOCK --- libc-top-half/musl/src/internal/lock.h | 16 ++++++++-------- libc-top-half/musl/src/locale/newlocale.c | 4 ++-- libc-top-half/musl/src/locale/setlocale.c | 10 +++++----- libc-top-half/musl/src/stdio/__lockfile.c | 4 ++-- libc-top-half/musl/src/stdio/ofl.c | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libc-top-half/musl/src/internal/lock.h b/libc-top-half/musl/src/internal/lock.h index 75d405524..feacd7ce8 100644 --- a/libc-top-half/musl/src/internal/lock.h +++ b/libc-top-half/musl/src/internal/lock.h @@ -7,8 +7,8 @@ // - __lock_t: the type of a lock variable // - __lock_ptr_t: the type of a pointer to a lock variable // - __LOCK_INIT: initializer for a lock variable -// - STRONG_LOCK/STRONG_UNLOCK: functions to acquire/release a lock for a critical section that contains -// potential context switch points, and thus must be executed even in cooperative threading mode. +// - LOCK/UNLOCK: functions to acquire/release a lock for a critical section that contains +// potential context switch points, and thus must be executed even in cooperative threading mode. // - WEAK_LOCK/WEAK_UNLOCK: functions to acquire/release a lock for a critical section that does not contain any context switch points, // and thus can be no-ops in cooperative threading mode. @@ -28,8 +28,8 @@ hidden void __lock(struct __coop_lock *lock); hidden void __unlock(struct __coop_lock *lock); - #define STRONG_LOCK(x) __lock(x) - #define STRONG_UNLOCK(x) __unlock(x) + #define LOCK(x) __lock(x) + #define UNLOCK(x) __unlock(x) #define WEAK_LOCK(x) ((void)0) #define WEAK_UNLOCK(x) ((void)0) #elif defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) @@ -41,14 +41,14 @@ hidden void __lock(volatile int *); hidden void __unlock(volatile int *); - #define STRONG_LOCK(x) __lock(x) - #define STRONG_UNLOCK(x) __unlock(x) + #define LOCK(x) __lock(x) + #define UNLOCK(x) __unlock(x) #define WEAK_LOCK(x) __lock(x) #define WEAK_UNLOCK(x) __unlock(x) #else // No locking needed. - #define STRONG_LOCK(x) ((void)0) - #define STRONG_UNLOCK(x) ((void)0) + #define LOCK(x) ((void)0) + #define UNLOCK(x) ((void)0) #define WEAK_LOCK(x) ((void)0) #define WEAK_UNLOCK(x) ((void)0) #endif diff --git a/libc-top-half/musl/src/locale/newlocale.c b/libc-top-half/musl/src/locale/newlocale.c index 814adab0e..11c778557 100644 --- a/libc-top-half/musl/src/locale/newlocale.c +++ b/libc-top-half/musl/src/locale/newlocale.c @@ -63,9 +63,9 @@ static locale_t do_newlocale(int mask, const char *name, locale_t loc) locale_t __newlocale(int mask, const char *name, locale_t loc) { - STRONG_LOCK(__locale_lock); + LOCK(__locale_lock); loc = do_newlocale(mask, name, loc); - STRONG_UNLOCK(__locale_lock); + UNLOCK(__locale_lock); return loc; } diff --git a/libc-top-half/musl/src/locale/setlocale.c b/libc-top-half/musl/src/locale/setlocale.c index 18f2a2c1e..360c44376 100644 --- a/libc-top-half/musl/src/locale/setlocale.c +++ b/libc-top-half/musl/src/locale/setlocale.c @@ -13,7 +13,7 @@ char *setlocale(int cat, const char *name) if ((unsigned)cat > LC_ALL) return 0; - STRONG_LOCK(__locale_lock); + LOCK(__locale_lock); /* For LC_ALL, setlocale is required to return a string which * encodes the current setting for all categories. The format of @@ -35,7 +35,7 @@ char *setlocale(int cat, const char *name) } lm = __get_locale(i, part); if (lm == LOC_MAP_FAILED) { - STRONG_UNLOCK(__locale_lock); + UNLOCK(__locale_lock); return 0; } tmp_locale.cat[i] = lm; @@ -56,14 +56,14 @@ char *setlocale(int cat, const char *name) s += l+1; } *--s = 0; - STRONG_UNLOCK(__locale_lock); + UNLOCK(__locale_lock); return same==LC_ALL ? (char *)part : buf; } if (name) { lm = __get_locale(cat, name); if (lm == LOC_MAP_FAILED) { - STRONG_UNLOCK(__locale_lock); + UNLOCK(__locale_lock); return 0; } libc.global_locale.cat[cat] = lm; @@ -72,7 +72,7 @@ char *setlocale(int cat, const char *name) } char *ret = lm ? (char *)lm->name : "C"; - STRONG_UNLOCK(__locale_lock); + UNLOCK(__locale_lock); return ret; } diff --git a/libc-top-half/musl/src/stdio/__lockfile.c b/libc-top-half/musl/src/stdio/__lockfile.c index 042742547..77878783a 100644 --- a/libc-top-half/musl/src/stdio/__lockfile.c +++ b/libc-top-half/musl/src/stdio/__lockfile.c @@ -9,13 +9,13 @@ int __lockfile(FILE *f) if (f->lock.owner == __pthread_self()->tid) return 0; - STRONG_LOCK(&f->lock); + LOCK(&f->lock); return 1; } void __unlockfile(FILE *f) { - STRONG_UNLOCK(&f->lock); + UNLOCK(&f->lock); } #else int __lockfile(FILE *f) diff --git a/libc-top-half/musl/src/stdio/ofl.c b/libc-top-half/musl/src/stdio/ofl.c index 2a298a2f8..d69ee2805 100644 --- a/libc-top-half/musl/src/stdio/ofl.c +++ b/libc-top-half/musl/src/stdio/ofl.c @@ -10,11 +10,11 @@ __lock_t *const __stdio_ofl_lockptr = ofl_lock; FILE **__ofl_lock() { - STRONG_LOCK(ofl_lock); + LOCK(ofl_lock); return &ofl_head; } void __ofl_unlock() { - STRONG_UNLOCK(ofl_lock); + UNLOCK(ofl_lock); } From 1f67537f4ab8a5c0268a744f2597018166af4bbe Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:21:50 +0000 Subject: [PATCH 08/28] Rename STRONG_LOCK --- libc-bottom-half/sources/preopens.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libc-bottom-half/sources/preopens.c b/libc-bottom-half/sources/preopens.c index 84738c53f..077c12318 100644 --- a/libc-bottom-half/sources/preopens.c +++ b/libc-bottom-half/sources/preopens.c @@ -220,11 +220,11 @@ static bool prefix_matches(const char *prefix, size_t prefix_len, /// This function takes ownership of `prefix`. static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) { - STRONG_LOCK(lock); + LOCK(lock); int r = internal_register_preopened_fd_unlocked(fd, relprefix); - STRONG_UNLOCK(lock); + UNLOCK(lock); return r; } @@ -263,7 +263,7 @@ int __wasilibc_find_abspath(const char *path, const char **abs_prefix, // recently added preopens take precedence over less recently addded ones. size_t match_len = 0; int fd = -1; - STRONG_LOCK(lock); + LOCK(lock); for (size_t i = num_preopens; i > 0; --i) { const preopen *pre = &preopens[i - 1]; const char *prefix = pre->prefix; @@ -278,7 +278,7 @@ int __wasilibc_find_abspath(const char *path, const char **abs_prefix, *abs_prefix = prefix; } } - STRONG_UNLOCK(lock); + UNLOCK(lock); if (fd == -1) { errno = ENOENT; @@ -306,11 +306,11 @@ void __wasilibc_populate_preopens(void) { return; } - STRONG_LOCK(lock); + LOCK(lock); // Check whether another thread initialized the preopens already. if (preopens_populated) { - STRONG_UNLOCK(lock); + UNLOCK(lock); return; } @@ -381,7 +381,7 @@ void __wasilibc_populate_preopens(void) { // Preopens are now initialized. preopens_populated = true; - STRONG_UNLOCK(lock); + UNLOCK(lock); return; #ifdef __wasip1__ @@ -393,7 +393,7 @@ void __wasilibc_populate_preopens(void) { } void __wasilibc_reset_preopens(void) { - STRONG_LOCK(lock); + LOCK(lock); if (num_preopens) { for (int i = 0; i < num_preopens; ++i) { @@ -410,5 +410,5 @@ void __wasilibc_reset_preopens(void) { assert_invariants(); - STRONG_UNLOCK(lock); + UNLOCK(lock); } From 94dd50313ab9efa464d10872122df78b1f528ed8 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:27:32 +0000 Subject: [PATCH 09/28] Change cwd locking --- libc-bottom-half/sources/getcwd.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libc-bottom-half/sources/getcwd.c b/libc-bottom-half/sources/getcwd.c index 576508620..1c7276645 100644 --- a/libc-bottom-half/sources/getcwd.c +++ b/libc-bottom-half/sources/getcwd.c @@ -8,27 +8,32 @@ char *__wasilibc_cwd = "/"; #ifdef _REENTRANT static __lock_t lock[1]; +// Critical section contains no yield points, so we can use weak locks. +void __wasilibc_cwd_lock(void) { WEAK_LOCK(lock); } +void __wasilibc_cwd_unlock(void) { WEAK_UNLOCK(lock); } +#else +#define __wasilibc_cwd_lock() (void)0 +#define __wasilibc_cwd_unlock() (void)0 #endif char *getcwd(char *buf, size_t size) { - // Critical section contains no yield points, so we can use weak locks. - WEAK_LOCK(lock); + __wasilibc_cwd_lock(); if (!buf) { buf = strdup(__wasilibc_cwd); if (!buf) { errno = ENOMEM; - WEAK_UNLOCK(lock); + __wasilibc_cwd_unlock(); return NULL; } } else { size_t len = strlen(__wasilibc_cwd); if (size < len + 1) { errno = ERANGE; - WEAK_UNLOCK(lock); + __wasilibc_cwd_unlock(); return NULL; } strcpy(buf, __wasilibc_cwd); } - WEAK_UNLOCK(lock); + __wasilibc_cwd_unlock(); return buf; } From 5d6abcf22ac2166e893fd02a00dc45415db1f768 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:39:30 +0000 Subject: [PATCH 10/28] Build fixes --- libc-top-half/musl/src/stdio/__lockfile.c | 1 + .../musl/src/thread/wasi-threads/__wait.c | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/libc-top-half/musl/src/stdio/__lockfile.c b/libc-top-half/musl/src/stdio/__lockfile.c index 77878783a..a325ffe40 100644 --- a/libc-top-half/musl/src/stdio/__lockfile.c +++ b/libc-top-half/musl/src/stdio/__lockfile.c @@ -1,5 +1,6 @@ #include "stdio_impl.h" #include "pthread_impl.h" +#inculde #ifdef __wasi_cooperative_threads__ #include "lock.h" diff --git a/libc-top-half/musl/src/thread/wasi-threads/__wait.c b/libc-top-half/musl/src/thread/wasi-threads/__wait.c index 9484c0f3d..8248571f9 100644 --- a/libc-top-half/musl/src/thread/wasi-threads/__wait.c +++ b/libc-top-half/musl/src/thread/wasi-threads/__wait.c @@ -64,3 +64,28 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) } if (waiters) a_dec(waiters); } + +void __wake(volatile void *addr, int cnt, int priv) +{ + if (priv) priv = FUTEX_PRIVATE; + if (cnt<0) cnt = INT_MAX; +#ifdef __wasilibc_unmodified_upstream + __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || + __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); +#else +#ifdef _REENTRANT + __builtin_wasm_memory_atomic_notify((int*)addr, cnt); +#endif +#endif +} + +void __futexwait(volatile void *addr, int val, int priv) +{ +#ifdef __wasilibc_unmodified_upstream + if (priv) priv = FUTEX_PRIVATE; + __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || + __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); +#else + __wait(addr, NULL, val, priv); +#endif +} \ No newline at end of file From cf950b7901ab05c4485a70f9a514476b0240cd5e Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:42:22 +0000 Subject: [PATCH 11/28] Build fixes --- libc-top-half/musl/src/stdio/__lockfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc-top-half/musl/src/stdio/__lockfile.c b/libc-top-half/musl/src/stdio/__lockfile.c index a325ffe40..25b19e60c 100644 --- a/libc-top-half/musl/src/stdio/__lockfile.c +++ b/libc-top-half/musl/src/stdio/__lockfile.c @@ -1,6 +1,6 @@ #include "stdio_impl.h" #include "pthread_impl.h" -#inculde +#include #ifdef __wasi_cooperative_threads__ #include "lock.h" From 4311c910ee9457f139198fa99c709d5f5de52fcf Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:48:24 +0000 Subject: [PATCH 12/28] Symbol fixes --- expected/wasm32-wasip1/defined-symbols.txt | 2 ++ libc-top-half/musl/src/exit/atexit.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/expected/wasm32-wasip1/defined-symbols.txt b/expected/wasm32-wasip1/defined-symbols.txt index 562d70527..3dc1c6f78 100644 --- a/expected/wasm32-wasip1/defined-symbols.txt +++ b/expected/wasm32-wasip1/defined-symbols.txt @@ -75,6 +75,7 @@ __ftello __ftello_unlocked __funcs_on_exit __funcs_on_quick_exit +__futexwait __futimesat __fwritable __fwritex @@ -285,6 +286,7 @@ __uflow __unlist_locked_file __uselocale __utc +__wait __wasi_args_get __wasi_args_sizes_get __wasi_clock_res_get diff --git a/libc-top-half/musl/src/exit/atexit.c b/libc-top-half/musl/src/exit/atexit.c index d52ae8267..f13d540a0 100644 --- a/libc-top-half/musl/src/exit/atexit.c +++ b/libc-top-half/musl/src/exit/atexit.c @@ -26,7 +26,7 @@ static int slot; // All locks here can be weak, because the locking is only needed to protect against // concurrent manipulation of the handler table, which hits no context switch points. -__lock_t lock[1]; +static __lock_t lock[1]; __lock_t *const __atexit_lockptr = lock; #endif From f68bf5a76d9b5c36276dd4ccc0717759cc44653e Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:52:24 +0000 Subject: [PATCH 13/28] Symbol fixes --- expected/wasm32-wasip1-threads/defined-symbols.txt | 1 + expected/wasm32-wasip1/defined-symbols.txt | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/expected/wasm32-wasip1-threads/defined-symbols.txt b/expected/wasm32-wasip1-threads/defined-symbols.txt index 4fb5d53fc..332ae8e39 100644 --- a/expected/wasm32-wasip1-threads/defined-symbols.txt +++ b/expected/wasm32-wasip1-threads/defined-symbols.txt @@ -81,6 +81,7 @@ __ftello __ftello_unlocked __funcs_on_exit __funcs_on_quick_exit +__futexwait __futimesat __fwritable __fwritex diff --git a/expected/wasm32-wasip1/defined-symbols.txt b/expected/wasm32-wasip1/defined-symbols.txt index 3dc1c6f78..562d70527 100644 --- a/expected/wasm32-wasip1/defined-symbols.txt +++ b/expected/wasm32-wasip1/defined-symbols.txt @@ -75,7 +75,6 @@ __ftello __ftello_unlocked __funcs_on_exit __funcs_on_quick_exit -__futexwait __futimesat __fwritable __fwritex @@ -286,7 +285,6 @@ __uflow __unlist_locked_file __uselocale __utc -__wait __wasi_args_get __wasi_args_sizes_get __wasi_clock_res_get From 73081cf5298f3636f74701cdbd9d0ffb731057dd Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 20:59:09 +0000 Subject: [PATCH 14/28] Symbol fixes --- expected/wasm32-wasip1-threads/defined-symbols.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/expected/wasm32-wasip1-threads/defined-symbols.txt b/expected/wasm32-wasip1-threads/defined-symbols.txt index 332ae8e39..1d2f3c63c 100644 --- a/expected/wasm32-wasip1-threads/defined-symbols.txt +++ b/expected/wasm32-wasip1-threads/defined-symbols.txt @@ -309,6 +309,7 @@ __unlockfile __uselocale __utc __wait +__wake __wasi_args_get __wasi_args_sizes_get __wasi_clock_res_get From 47e08ba05d8e43f344d550a50590c04d5f6d20a7 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 21:01:31 +0000 Subject: [PATCH 15/28] Disable shared builds --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e261d183..63f20aa17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,8 @@ elseif(TARGET_TRIPLE MATCHES "-wasip2$") set(SHARED ON) elseif(TARGET_TRIPLE MATCHES "-wasip3$") set(WASI p3) - set(SHARED ON) + # TODO: There are currently issues with shared libraries on wasip3, so disable for now. + set(SHARED OFF) else() message(FATAL_ERROR "Unknown WASI target triple: ${TARGET_TRIPLE}") endif() From 1210dca331a86c87c809548125dfcc524c097ca3 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 21:32:10 +0000 Subject: [PATCH 16/28] Update symbols for WASIP3 --- expected/wasm32-wasip3/defined-symbols.txt | 32 ++++++++++++++++++++ expected/wasm32-wasip3/predefined-macros.txt | 4 +++ expected/wasm32-wasip3/undefined-symbols.txt | 20 ++++++++++++ 3 files changed, 56 insertions(+) diff --git a/expected/wasm32-wasip3/defined-symbols.txt b/expected/wasm32-wasip3/defined-symbols.txt index 61ac1ad71..ff13a6498 100644 --- a/expected/wasm32-wasip3/defined-symbols.txt +++ b/expected/wasm32-wasip3/defined-symbols.txt @@ -12,8 +12,11 @@ __ENOMEM __SIG_ERR __SIG_IGN __acquire_ptc +__aio_close __asctime_r __assert_fail +__at_quick_exit_lockptr +__atexit_lockptr __c_dot_utf8 __c_dot_utf8_locale __c_locale @@ -22,6 +25,7 @@ __clock_gettime __clock_nanosleep __component_type_object_force_link_wasip3 __component_type_object_force_link_wasip3_public_use_in_this_compilation_unit +__copy_tls __cos __cosdf __cosl @@ -143,7 +147,11 @@ __libc_calloc __libc_free __libc_malloc __loc_is_allocated +__locale_lock +__locale_lockptr __localtime_r +__lock +__lockfile __log2_data __log2f_data __log_data @@ -208,6 +216,7 @@ __pthread_tsd_size __putenv __qsort_r __rand48_step +__random_lockptr __reallocarray __release_ptc __rem_pio2 @@ -235,6 +244,7 @@ __stdin_used __stdio_close __stdio_exit __stdio_exit_needed +__stdio_ofl_lockptr __stdio_read __stdio_seek __stdio_write @@ -266,6 +276,7 @@ __tan __tandf __tanl __testcancel +__thread_list_lock __tl_lock __tl_unlock __tm_to_secs @@ -285,8 +296,13 @@ __tre_mem_new_impl __tsearch_balance __uflow __unlist_locked_file +__unlock +__unlockfile __uselocale __utc +__waitlist_wait_on +__waitlist_wake_all +__waitlist_wake_one __wasi_init_tp __wasi_sockets_services_db __wasi_sockets_utils__any_addr @@ -303,6 +319,8 @@ __wasilibc_add_file __wasilibc_add_tcp_socket __wasilibc_add_udp_socket __wasilibc_cwd +__wasilibc_cwd_lock +__wasilibc_cwd_unlock __wasilibc_deinitialize_environ __wasilibc_dttoif __wasilibc_ensure_environ @@ -1466,7 +1484,9 @@ vwscanf wasip3_backpressure_dec wasip3_backpressure_inc wasip3_context_get_0 +wasip3_context_get_1 wasip3_context_set_0 +wasip3_context_set_1 wasip3_list_string_free wasip3_list_tuple2_string_string_free wasip3_list_u8_free @@ -1479,7 +1499,19 @@ wasip3_subtask_block_on wasip3_subtask_cancel wasip3_subtask_drop wasip3_task_cancel +wasip3_thread_index +wasip3_thread_new_indirect +wasip3_thread_suspend +wasip3_thread_suspend_cancellable +wasip3_thread_suspend_to +wasip3_thread_suspend_to_cancellable +wasip3_thread_suspend_to_suspended +wasip3_thread_suspend_to_suspended_cancellable +wasip3_thread_unsuspend wasip3_thread_yield +wasip3_thread_yield_cancellable +wasip3_thread_yield_to_suspended +wasip3_thread_yield_to_suspended_cancellable wasip3_tuple2_string_string_free wasip3_waitable_block_on wasip3_waitable_join diff --git a/expected/wasm32-wasip3/predefined-macros.txt b/expected/wasm32-wasip3/predefined-macros.txt index 8e2f62089..ac77e6d35 100644 --- a/expected/wasm32-wasip3/predefined-macros.txt +++ b/expected/wasm32-wasip3/predefined-macros.txt @@ -1734,6 +1734,8 @@ #define SEEK_SET 0 #define SEGSIZE 512 #define SEM_FAILED ((sem_t *)0) +#define SEM_NSEMS_MAX 256 +#define SEM_VALUE_MAX 0x7fffffff #define SERVFAIL ns_r_servfail #define SHORTBITS (sizeof(short) * 8) #define SHRT_MAX 0x7fff @@ -2429,6 +2431,7 @@ #define _POSIX_VERSION 200809L #define _PTHREAD_H #define _PTRDIFF_T +#define _REENTRANT 1 #define _REGEX_H #define _SCHED_H #define _SC_2_CHAR_TERM 95 @@ -3133,6 +3136,7 @@ #define __va_copy(d,s) __builtin_va_copy(d, s) #define __wasi__ 1 #define __wasi_api_h +#define __wasi_cooperative_threads__ #define __wasi_libc_busywait_h #define __wasi_libc_environ_h #define __wasi_libc_find_relpath_h diff --git a/expected/wasm32-wasip3/undefined-symbols.txt b/expected/wasm32-wasip3/undefined-symbols.txt index a9d8a373b..d7b9b134e 100644 --- a/expected/wasm32-wasip3/undefined-symbols.txt +++ b/expected/wasm32-wasip3/undefined-symbols.txt @@ -2,7 +2,9 @@ __addtf3 __backpressure_dec __backpressure_inc __context_get_0 +__context_get_1 __context_set_0 +__context_set_1 __data_end __divtf3 __eqtf2 @@ -26,7 +28,20 @@ __subtask_cancel __subtask_drop __subtf3 __task_cancel +__thread_index +__thread_new_indirect +__thread_suspend +__thread_suspend_cancellable +__thread_suspend_to +__thread_suspend_to_cancellable +__thread_suspend_to_suspended +__thread_suspend_to_suspended_cancellable +__thread_unsuspend __thread_yield +__thread_yield_cancellable +__thread_yield_to_suspended +__thread_yield_to_suspended_cancellable +__tls_align __trunctfdf2 __trunctfsf2 __unordtf2 @@ -36,6 +51,10 @@ __waitable_set_new __waitable_set_poll __waitable_set_wait __wasm_call_ctors +__wasm_component_model_builtin_context_get_0 +__wasm_component_model_builtin_context_get_1 +__wasm_component_model_builtin_context_set_0 +__wasm_first_page_end __wasm_import_environment_get_arguments __wasm_import_environment_get_environment __wasm_import_environment_get_initial_cwd @@ -129,6 +148,7 @@ __wasm_import_terminal_output_terminal_output_drop __wasm_import_terminal_stderr_get_terminal_stderr __wasm_import_terminal_stdin_get_terminal_stdin __wasm_import_terminal_stdout_get_terminal_stdout +__wasm_init_tls filesystem_future_result_void_error_code__cancel_read filesystem_future_result_void_error_code__cancel_write filesystem_future_result_void_error_code__drop_readable From e7407c7b45deb5f5ea68153df51600c1bf6f9c4d Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 21:41:14 +0000 Subject: [PATCH 17/28] Bump wasm-component-ld --- cmake/wasm-component-ld.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/wasm-component-ld.cmake b/cmake/wasm-component-ld.cmake index 2e7976602..0314df308 100644 --- a/cmake/wasm-component-ld.cmake +++ b/cmake/wasm-component-ld.cmake @@ -10,7 +10,7 @@ if (NOT WASM_COMPONENT_LD_EXECUTABLE) ba_download( wasm-component-ld "https://github.com/bytecodealliance/wasm-component-ld" - "v0.5.19" + "v0.5.20" ) ExternalProject_Get_Property(wasm-component-ld SOURCE_DIR) set(WASM_COMPONENT_LD_EXECUTABLE "${SOURCE_DIR}/wasm-component-ld") From 29fb9846bc63ed6217f9ec3f9834eb5775471898 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 21:42:51 +0000 Subject: [PATCH 18/28] Undefined signal fix --- expected/wasm32-wasip3/undefined-symbols.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/expected/wasm32-wasip3/undefined-symbols.txt b/expected/wasm32-wasip3/undefined-symbols.txt index 6f3689463..d7b9b134e 100644 --- a/expected/wasm32-wasip3/undefined-symbols.txt +++ b/expected/wasm32-wasip3/undefined-symbols.txt @@ -41,10 +41,7 @@ __thread_yield __thread_yield_cancellable __thread_yield_to_suspended __thread_yield_to_suspended_cancellable -<<<<<<< sy/wasip3-locks __tls_align -======= ->>>>>>> main __trunctfdf2 __trunctfsf2 __unordtf2 From 28d741f30215a7d0da4e4a2812c3c5bb774e30b5 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 22:41:52 +0000 Subject: [PATCH 19/28] Bump wasm-component-ld --- cmake/wasm-component-ld.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/wasm-component-ld.cmake b/cmake/wasm-component-ld.cmake index 0314df308..d0b8b417e 100644 --- a/cmake/wasm-component-ld.cmake +++ b/cmake/wasm-component-ld.cmake @@ -10,7 +10,7 @@ if (NOT WASM_COMPONENT_LD_EXECUTABLE) ba_download( wasm-component-ld "https://github.com/bytecodealliance/wasm-component-ld" - "v0.5.20" + "v0.5.21" ) ExternalProject_Get_Property(wasm-component-ld SOURCE_DIR) set(WASM_COMPONENT_LD_EXECUTABLE "${SOURCE_DIR}/wasm-component-ld") From 93ab9e4b31d2721a880d0f8efb53e48f690c544f Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 22:46:49 +0000 Subject: [PATCH 20/28] Symbol fixes --- expected/wasm32-wasip3/predefined-macros.txt | 1 + expected/wasm32-wasip3/undefined-symbols.txt | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/expected/wasm32-wasip3/predefined-macros.txt b/expected/wasm32-wasip3/predefined-macros.txt index ac77e6d35..f4176082a 100644 --- a/expected/wasm32-wasip3/predefined-macros.txt +++ b/expected/wasm32-wasip3/predefined-macros.txt @@ -3210,6 +3210,7 @@ #define __wasm32 1 #define __wasm32__ 1 #define __wasm__ 1 +#define __wasm_atomics__ 1 #define _tolower(a) ((a)|0x20) #define _toupper(a) ((a)&0x5f) #define acos(x) __tg_real_complex(acos, (x)) diff --git a/expected/wasm32-wasip3/undefined-symbols.txt b/expected/wasm32-wasip3/undefined-symbols.txt index d7b9b134e..bba58ed57 100644 --- a/expected/wasm32-wasip3/undefined-symbols.txt +++ b/expected/wasm32-wasip3/undefined-symbols.txt @@ -50,11 +50,6 @@ __waitable_set_drop __waitable_set_new __waitable_set_poll __waitable_set_wait -__wasm_call_ctors -__wasm_component_model_builtin_context_get_0 -__wasm_component_model_builtin_context_get_1 -__wasm_component_model_builtin_context_set_0 -__wasm_first_page_end __wasm_import_environment_get_arguments __wasm_import_environment_get_environment __wasm_import_environment_get_initial_cwd From bf037e98c6ff73638a95fe9a197c52d0a7dd444a Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 22:50:59 +0000 Subject: [PATCH 21/28] Add __wasm_call_ctors to undefined --- expected/wasm32-wasip3/undefined-symbols.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/expected/wasm32-wasip3/undefined-symbols.txt b/expected/wasm32-wasip3/undefined-symbols.txt index bba58ed57..2d644ca97 100644 --- a/expected/wasm32-wasip3/undefined-symbols.txt +++ b/expected/wasm32-wasip3/undefined-symbols.txt @@ -50,6 +50,7 @@ __waitable_set_drop __waitable_set_new __waitable_set_poll __waitable_set_wait +__wasm_call_ctors __wasm_import_environment_get_arguments __wasm_import_environment_get_environment __wasm_import_environment_get_initial_cwd From 4bd86350649de127e3e175b87c6229b710e513e1 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 20 Feb 2026 22:55:14 +0000 Subject: [PATCH 22/28] Add component-model-threading feature --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bb51b2c05..d24aeec96 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -126,6 +126,7 @@ function(register_test test_name executable_name) endif() if (WASI STREQUAL "p3") list(APPEND wasmtime_args --wasm component-model-async) + list(APPEND wasmtime_args --wasm component-model-threading) list(APPEND wasmtime_args --wasi p3) endif() From a19d2cf45d7cc216530daf348395f5d20deb9a13 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Sat, 21 Feb 2026 10:25:11 +0000 Subject: [PATCH 23/28] Fix locks --- libc-top-half/musl/src/stdio/vsnprintf.c | 2 +- libc-top-half/musl/src/stdio/vswprintf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libc-top-half/musl/src/stdio/vsnprintf.c b/libc-top-half/musl/src/stdio/vsnprintf.c index 48c3aef7e..4d8366baf 100644 --- a/libc-top-half/musl/src/stdio/vsnprintf.c +++ b/libc-top-half/musl/src/stdio/vsnprintf.c @@ -41,7 +41,7 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) .lbf = EOF, .write = sn_write, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .lock = -1, + .lock = __STDIO_LOCK_INIT, #endif .buf = buf, .cookie = &c, diff --git a/libc-top-half/musl/src/stdio/vswprintf.c b/libc-top-half/musl/src/stdio/vswprintf.c index cab94cba7..d17da02ba 100644 --- a/libc-top-half/musl/src/stdio/vswprintf.c +++ b/libc-top-half/musl/src/stdio/vswprintf.c @@ -44,7 +44,7 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis .lbf = EOF, .write = sw_write, #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) - .lock = -1, + .lock = __STDIO_LOCK_INIT, #endif .buf = buf, .buf_size = sizeof buf, From 207dc0d8b54561b864aaf09c08ce92c20a6a200d Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Sat, 21 Feb 2026 10:30:58 +0000 Subject: [PATCH 24/28] Fix shared linking --- CMakeLists.txt | 3 +-- libc-top-half/musl/src/internal/stdio_impl.h | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 63f20aa17..5e261d183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,8 +68,7 @@ elseif(TARGET_TRIPLE MATCHES "-wasip2$") set(SHARED ON) elseif(TARGET_TRIPLE MATCHES "-wasip3$") set(WASI p3) - # TODO: There are currently issues with shared libraries on wasip3, so disable for now. - set(SHARED OFF) + set(SHARED ON) else() message(FATAL_ERROR "Unknown WASI target triple: ${TARGET_TRIPLE}") endif() diff --git a/libc-top-half/musl/src/internal/stdio_impl.h b/libc-top-half/musl/src/internal/stdio_impl.h index 7ea811393..cfd476715 100644 --- a/libc-top-half/musl/src/internal/stdio_impl.h +++ b/libc-top-half/musl/src/internal/stdio_impl.h @@ -84,8 +84,9 @@ extern hidden FILE *volatile __stdout_used; extern hidden FILE *volatile __stderr_used; #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) -hidden int __lockfile(FILE *); -hidden void __unlockfile(FILE *); +// Needs to be unhidden because they're used by the emulated signal implementation +int __lockfile(FILE *); +void __unlockfile(FILE *); #endif hidden size_t __stdio_read(FILE *, unsigned char *, size_t); From a6ffb7e329d6ef69cfed8a095c4bc7f07723050c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Sat, 21 Feb 2026 10:39:45 +0000 Subject: [PATCH 25/28] Retrigger CI From 518371afb4c896ea4d1df740d700dd4ed2523ece Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Sat, 21 Feb 2026 10:53:41 +0000 Subject: [PATCH 26/28] Change init lock --- libc-top-half/musl/src/thread/wasi-threads/pthread_create.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libc-top-half/musl/src/thread/wasi-threads/pthread_create.c b/libc-top-half/musl/src/thread/wasi-threads/pthread_create.c index 879b48c1f..4d1c02f16 100644 --- a/libc-top-half/musl/src/thread/wasi-threads/pthread_create.c +++ b/libc-top-half/musl/src/thread/wasi-threads/pthread_create.c @@ -349,7 +349,9 @@ weak_alias(dummy_file, __stderr_used); static void init_file_lock(FILE *f) { +#ifndef __wasi_cooperative_threads__ if (f && f->lock<0) f->lock = 0; +#endif } int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) From 4fb6925213248759a81db7ed38572f03d26b013c Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Sat, 21 Feb 2026 11:00:09 +0000 Subject: [PATCH 27/28] Disable dynamic linking --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e261d183..b3bb3c019 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,8 @@ elseif(TARGET_TRIPLE MATCHES "-wasip2$") set(SHARED ON) elseif(TARGET_TRIPLE MATCHES "-wasip3$") set(WASI p3) - set(SHARED ON) + # There seems to be some dynamic linking issues, especially with errno, for waspi3 + set(SHARED OFF) else() message(FATAL_ERROR "Unknown WASI target triple: ${TARGET_TRIPLE}") endif() From 29f8f5135c2b8bfe1a3b18978378f72431f92c14 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Sat, 21 Feb 2026 11:04:20 +0000 Subject: [PATCH 28/28] Reenable shared lib --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3bb3c019..5e261d183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,8 +68,7 @@ elseif(TARGET_TRIPLE MATCHES "-wasip2$") set(SHARED ON) elseif(TARGET_TRIPLE MATCHES "-wasip3$") set(WASI p3) - # There seems to be some dynamic linking issues, especially with errno, for waspi3 - set(SHARED OFF) + set(SHARED ON) else() message(FATAL_ERROR "Unknown WASI target triple: ${TARGET_TRIPLE}") endif()