From ac6fbf74fc7f2307f4db2d1c3c4980a8713b3e48 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sun, 6 Dec 2020 21:30:39 +0100 Subject: [PATCH 01/12] Reapply emscripten patches --- system/lib/libc/README.md | 3 +- system/lib/libc/musl/include/setjmp.h | 2 +- .../libc/musl/src/errno/__errno_location.c | 4 +- system/lib/libc/musl/src/exit/abort.c | 4 +- system/lib/libc/musl/src/internal/libm.h | 17 ++++--- .../lib/libc/musl/src/internal/locale_impl.h | 2 +- .../lib/libc/musl/src/internal/pthread_impl.h | 2 +- system/lib/libc/musl/src/internal/syscall.h | 51 +++++++++---------- system/lib/libc/musl/src/linux/sbrk.c | 3 +- system/lib/libc/musl/src/math/sqrt.c | 2 +- system/lib/libc/musl/src/math/sqrtf.c | 2 +- .../lib/libc/musl/src/network/freeaddrinfo.c | 2 +- system/lib/libc/musl/src/sched/sched_yield.c | 4 +- system/lib/libc/musl/src/stat/fchmod.c | 2 +- system/lib/libc/musl/src/stat/fstatat.c | 2 +- system/lib/libc/musl/src/stdio/__lockfile.c | 4 +- system/lib/libc/musl/src/stdio/__stdio_read.c | 3 +- .../lib/libc/musl/src/stdio/__stdio_write.c | 2 +- system/lib/libc/musl/src/stdio/stdout.c | 4 +- system/lib/libc/musl/src/stdio/vfprintf.c | 2 +- system/lib/libc/musl/src/string/memcmp.c | 2 +- system/lib/libc/musl/src/thread/__timedwait.c | 8 +-- .../musl/src/thread/pthread_mutex_timedlock.c | 2 +- system/lib/libc/musl/src/time/clock_gettime.c | 2 +- .../lib/libc/musl/src/time/clock_nanosleep.c | 4 +- system/lib/libc/musl/src/time/clock_settime.c | 7 +-- system/lib/libc/musl/src/unistd/fchdir.c | 2 +- system/lib/libc/musl/src/unistd/fchown.c | 4 +- system/lib/libc/musl/src/unistd/fsync.c | 2 +- system/lib/libc/musl/src/unistd/pread.c | 2 +- system/lib/libc/musl/src/unistd/preadv.c | 2 +- system/lib/libc/musl/src/unistd/pwrite.c | 2 +- system/lib/libc/musl/src/unistd/pwritev.c | 2 +- system/lib/libc/musl/src/unistd/read.c | 2 +- system/lib/libc/musl/src/unistd/readv.c | 2 +- system/lib/libc/musl/src/unistd/write.c | 2 +- system/lib/libc/musl/src/unistd/writev.c | 4 +- 37 files changed, 81 insertions(+), 87 deletions(-) diff --git a/system/lib/libc/README.md b/system/lib/libc/README.md index 0094e8a96dfe7..c3e1aff134e5b 100644 --- a/system/lib/libc/README.md +++ b/system/lib/libc/README.md @@ -7,8 +7,7 @@ and use a script (`system/lib/update_musl.py`) to pull in updates. Some changes have been made to the version that was taken from upstream, including: - * Emscripten-specific changes (from before this readme existed). These should be marked with `XXX EMSCRIPTEN` in the source, or ifdefed with `#if __EMSCRIPTEN__`. They are mostly in pthreads code and hopefully temporary. - * Backporting an operator-precedence warning fix from 6e76e1540fc58a418494bf5eb832b556f9c5763e in the upstream version. + * Emscripten-specific changes (from before this readme existed). These should be marked with `XXX EMSCRIPTEN` in the source, or ifdefed with `#ifdef __EMSCRIPTEN__`. They are mostly in pthreads code and hopefully temporary. * Switch to using the wasi `fd_write` syscall instead of `writev`. * Simplify stdout stream handling: do not support seeking, terminal handling, etc., as it just increases code size and Emscripten doesn't have those features anyhow. * Setting `_POSIX_REALTIME_SIGNALS` and `_POSIX_SPAWN` macros to -1, to exclude unsupported functions. diff --git a/system/lib/libc/musl/include/setjmp.h b/system/lib/libc/musl/include/setjmp.h index 6fb1a02510485..b79a99ebd1ed7 100644 --- a/system/lib/libc/musl/include/setjmp.h +++ b/system/lib/libc/musl/include/setjmp.h @@ -26,7 +26,7 @@ typedef struct __jmp_buf_tag { || defined(_BSD_SOURCE) typedef jmp_buf sigjmp_buf; /* XXX EMSCRIPTEN: No signals support, alias sigsetjmp and siglongjmp to their non-signals counterparts. */ -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #define sigsetjmp(buf, x) setjmp((buf)) #define siglongjmp(buf, val) longjmp(buf, val) #else diff --git a/system/lib/libc/musl/src/errno/__errno_location.c b/system/lib/libc/musl/src/errno/__errno_location.c index 05f55d9eaf7ad..49b3f535f3509 100644 --- a/system/lib/libc/musl/src/errno/__errno_location.c +++ b/system/lib/libc/musl/src/errno/__errno_location.c @@ -1,7 +1,7 @@ #include #include "pthread_impl.h" -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // For emscripten we use TLS here instead of `__pthread_self`, so that in single // threaded builds this gets lowered away to normal global variable. static _Thread_local int __errno_storage = 0; @@ -9,7 +9,7 @@ static _Thread_local int __errno_storage = 0; int *__errno_location(void) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ return &__errno_storage; #else return &__pthread_self()->errno_val; diff --git a/system/lib/libc/musl/src/exit/abort.c b/system/lib/libc/musl/src/exit/abort.c index a6427d51d66e9..8ff8a8626ee07 100644 --- a/system/lib/libc/musl/src/exit/abort.c +++ b/system/lib/libc/musl/src/exit/abort.c @@ -6,13 +6,13 @@ #include "lock.h" #include "ksigaction.h" -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #include "emscripten_internal.h" #endif _Noreturn void abort(void) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ /* In emscripten we call out to JS to perform the actual abort where it can * produce a nice error. * Note that the JS library function is not called `abort` to avoid conflict diff --git a/system/lib/libc/musl/src/internal/libm.h b/system/lib/libc/musl/src/internal/libm.h index a47208aa6ad3c..9d8b892d5b3e8 100644 --- a/system/lib/libc/musl/src/internal/libm.h +++ b/system/lib/libc/musl/src/internal/libm.h @@ -144,6 +144,16 @@ static inline long double fp_barrierl(long double x) } #endif +#ifdef __EMSCRIPTEN__ +/* + * wasm doesn't have user-accessible floating point exceptions, so there's + * no point in trying to force expression evaluations to produce them. + */ +#define fp_force_evalf(x) +#define fp_force_eval(x) +#define fp_force_evall(x) +#define FORCE_EVAL(x) +#else /* fp_force_eval ensures that the input value is computed when that's otherwise unused. To prevent the constant folding of the input expression, an additional fp_barrier may be needed or a compilation @@ -177,13 +187,6 @@ static inline void fp_force_evall(long double x) } #endif -#ifdef __EMSCRIPTEN__ -/* - * asm.js doesn't have user-accessible floating point exceptions, so there's - * no point in trying to force expression evaluations to produce them. - */ -#define FORCE_EVAL(x) -#else #define FORCE_EVAL(x) do { \ if (sizeof(x) == sizeof(float)) { \ fp_force_evalf(x); \ diff --git a/system/lib/libc/musl/src/internal/locale_impl.h b/system/lib/libc/musl/src/internal/locale_impl.h index ed60d16000589..78afb09b4be30 100644 --- a/system/lib/libc/musl/src/internal/locale_impl.h +++ b/system/lib/libc/musl/src/internal/locale_impl.h @@ -31,7 +31,7 @@ hidden char *__gettextdomain(void); #define LOC_MAP_FAILED ((const struct __locale_map *)-1) -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // Disable message translation completely under emscripten since we don't // support loading any actual locale data, and even looking up the current // local via CURRENT_LOCALE via TLS is not free. diff --git a/system/lib/libc/musl/src/internal/pthread_impl.h b/system/lib/libc/musl/src/internal/pthread_impl.h index 7f3a5483c802f..22e944a39b846 100644 --- a/system/lib/libc/musl/src/internal/pthread_impl.h +++ b/system/lib/libc/musl/src/internal/pthread_impl.h @@ -223,7 +223,7 @@ static inline void __wake(volatile void *addr, int cnt, int priv) if (priv) priv = FUTEX_PRIVATE; if (cnt<0) cnt = INT_MAX; #ifdef __EMSCRIPTEN__ - emscripten_futex_wake(addr, (cnt)<0?INT_MAX:(cnt)); + emscripten_futex_wake(addr, cnt); #else __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); diff --git a/system/lib/libc/musl/src/internal/syscall.h b/system/lib/libc/musl/src/internal/syscall.h index 1a6c4313852d7..b4152b6145eff 100644 --- a/system/lib/libc/musl/src/internal/syscall.h +++ b/system/lib/libc/musl/src/internal/syscall.h @@ -30,7 +30,7 @@ typedef long syscall_arg_t; #endif -#ifdef __cplusplus +#ifdef __cplusplus // XXX Emscripten we need C linkage for this extern "C" { #endif hidden long __syscall_ret(unsigned long), @@ -40,14 +40,7 @@ hidden long __syscall_ret(unsigned long), } #endif -#ifndef __EMSCRIPTEN__ -#define __syscall1(n,a) __syscall1(n,__scc(a)) -#define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b)) -#define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c)) -#define __syscall4(n,a,b,c,d) __syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) -#define __syscall5(n,a,b,c,d,e) __syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) -#define __syscall6(n,a,b,c,d,e,f) __syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) -#else // __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #define __syscall_emscripten(n, ...) n(__VA_ARGS__) #define __syscall_emscripten0(n) __syscall_emscripten(n) #define __syscall_emscripten1(n,a) __syscall_emscripten(n,__scc(a)) @@ -56,7 +49,14 @@ hidden long __syscall_ret(unsigned long), #define __syscall_emscripten4(n,a,b,c,d) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d)) #define __syscall_emscripten5(n,a,b,c,d,e) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) #define __syscall_emscripten6(n,a,b,c,d,e,f) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) -#endif // __EMSCRIPTEN__ +#else // !defined(__EMSCRIPTEN__) +#define __syscall1(n,a) __syscall1(n,__scc(a)) +#define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b)) +#define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c)) +#define __syscall4(n,a,b,c,d) __syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall5(n,a,b,c,d,e) __syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall6(n,a,b,c,d,e,f) __syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#endif // !defined(__EMSCRIPTEN__) #define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n #define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) @@ -64,10 +64,10 @@ hidden long __syscall_ret(unsigned long), #define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b) #define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) -#ifndef __EMSCRIPTEN__ -#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) -#else +#ifdef __EMSCRIPTEN__ #define __syscall(...) __SYSCALL_DISP(__syscall_emscripten,__VA_ARGS__) +#else +#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) #endif #define syscall(...) __syscall_ret(__syscall(__VA_ARGS__)) @@ -75,7 +75,9 @@ hidden long __syscall_ret(unsigned long), #define socketcall(nm,a,b,c,d,e,f) __syscall_ret(__socketcall(nm,a,b,c,d,e,f)) #define socketcall_cp(nm,a,b,c,d,e,f) __syscall_ret(__socketcall_cp(nm,a,b,c,d,e,f)) -#ifndef __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ +#define __syscall_cp(...) __syscall(__VA_ARGS__) +#else // !defined(__EMSCRIPTEN__) #define __syscall_cp0(n) (__syscall_cp)(n,0,0,0,0,0,0) #define __syscall_cp1(n,a) (__syscall_cp)(n,__scc(a),0,0,0,0,0) #define __syscall_cp2(n,a,b) (__syscall_cp)(n,__scc(a),__scc(b),0,0,0,0) @@ -85,9 +87,7 @@ hidden long __syscall_ret(unsigned long), #define __syscall_cp6(n,a,b,c,d,e,f) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) #define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__) -#else // __EMSCRIPTEN__ -#define __syscall_cp(...) __syscall(__VA_ARGS__) -#endif // __EMSCRIPTEN__ +#endif // !defined(__EMSCRIPTEN__) #define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__)) @@ -408,7 +408,12 @@ hidden long __syscall_ret(unsigned long), #define SIOCGSTAMPNS_OLD 0x8907 #endif -#ifndef __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ +#define __sys_open2(x,pn,fl) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE)) +#define __sys_open3(x,pn,fl,mo) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE), __scc(mo)) +#define __sys_open_cp2(x,pn,fl) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE)) +#define __sys_open_cp3(x,pn,fl,mo) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE), __scc(mo)) +#else // !defined(__EMSCRIPTEN__) #ifdef SYS_open #define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE) #define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo) @@ -420,13 +425,7 @@ hidden long __syscall_ret(unsigned long), #define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) #define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) #endif -#else // __EMSCRIPTEN__ -#define __sys_open2(x,pn,fl) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE)) -#define __sys_open3(x,pn,fl,mo) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE), __scc(mo)) -#define __sys_open_cp2(x,pn,fl) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE)) -#define __sys_open_cp3(x,pn,fl,mo) __syscall_openat(__scc(AT_FDCWD), __scc(pn), __scc((fl)|O_LARGEFILE), __scc(mo)) -#endif - +#endif // !defined(__EMSCRIPTEN__) #define __sys_open(...) __SYSCALL_DISP(__sys_open,,__VA_ARGS__) #define sys_open(...) __syscall_ret(__sys_open(__VA_ARGS__)) @@ -445,7 +444,7 @@ hidden long __emulate_wait4(int, int *, int, void *, int); #define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d)) #define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d)) -#ifdef __cplusplus +#ifdef __cplusplus // XXX Emscripten static array size is a C99 feature, not permitted in C++ hidden void __procfdname(char __buf[], unsigned); #else hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned); diff --git a/system/lib/libc/musl/src/linux/sbrk.c b/system/lib/libc/musl/src/linux/sbrk.c index 8e3a9b6645d68..cf483a57fb329 100644 --- a/system/lib/libc/musl/src/linux/sbrk.c +++ b/system/lib/libc/musl/src/linux/sbrk.c @@ -1,4 +1,4 @@ -#if !__EMSCRIPTEN__ /* Emscripten controls sbrk itself */ +#ifndef __EMSCRIPTEN__ /* Emscripten controls sbrk itself */ #define _BSD_SOURCE #include #include @@ -11,4 +11,3 @@ void *sbrk(intptr_t inc) return (void *)__syscall(SYS_brk, 0); } #endif - diff --git a/system/lib/libc/musl/src/math/sqrt.c b/system/lib/libc/musl/src/math/sqrt.c index 6854c98381642..3b07abee8380a 100644 --- a/system/lib/libc/musl/src/math/sqrt.c +++ b/system/lib/libc/musl/src/math/sqrt.c @@ -27,7 +27,7 @@ double sqrt(double x) { // XXX EMSCRIPTEN: use the wasm instruction via clang builtin // See https://github.com/emscripten-core/emscripten/issues/9236 -#ifdef __wasm__ +#ifdef __EMSCRIPTEN__ return __builtin_sqrt(x); #else uint64_t ix, top, m; diff --git a/system/lib/libc/musl/src/math/sqrtf.c b/system/lib/libc/musl/src/math/sqrtf.c index fd74702691215..d1f3b9595ccd0 100644 --- a/system/lib/libc/musl/src/math/sqrtf.c +++ b/system/lib/libc/musl/src/math/sqrtf.c @@ -18,7 +18,7 @@ float sqrtf(float x) { // XXX EMSCRIPTEN: use the wasm instruction via clang builtin // See https://github.com/emscripten-core/emscripten/issues/9236 -#ifdef __wasm__ +#ifdef __EMSCRIPTEN__ return __builtin_sqrtf(x); #else uint32_t ix, m, m1, m0, even, ey; diff --git a/system/lib/libc/musl/src/network/freeaddrinfo.c b/system/lib/libc/musl/src/network/freeaddrinfo.c index c4016d9f7c246..68fdc09cb9e10 100644 --- a/system/lib/libc/musl/src/network/freeaddrinfo.c +++ b/system/lib/libc/musl/src/network/freeaddrinfo.c @@ -6,7 +6,7 @@ void freeaddrinfo(struct addrinfo *p) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // Emscripten's usage of this structure is very simple: we always allocate // ai_addr, and do not use the linked list aspect at all. There is also no // aliasing with aibuf. diff --git a/system/lib/libc/musl/src/sched/sched_yield.c b/system/lib/libc/musl/src/sched/sched_yield.c index 7bd3846fc239e..82a14a3914e95 100644 --- a/system/lib/libc/musl/src/sched/sched_yield.c +++ b/system/lib/libc/musl/src/sched/sched_yield.c @@ -1,7 +1,7 @@ #include #include "syscall.h" -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #include #include #include "threading_internal.h" @@ -9,7 +9,7 @@ int sched_yield() { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // SharedArrayBuffer and wasm threads do not support explicit yielding. // For now we at least call `emscripten_yield` which processes the event queue // (along with other essential tasks). diff --git a/system/lib/libc/musl/src/stat/fchmod.c b/system/lib/libc/musl/src/stat/fchmod.c index 58badd5c01bb8..ca2a6c783b2bd 100644 --- a/system/lib/libc/musl/src/stat/fchmod.c +++ b/system/lib/libc/musl/src/stat/fchmod.c @@ -9,7 +9,7 @@ int fchmod(int fd, mode_t mode) { int ret = __syscall(SYS_fchmod, fd, mode); -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ if (ret != -EBADF || !__wasi_fd_is_valid(fd)) return __syscall_ret(ret); #else diff --git a/system/lib/libc/musl/src/stat/fstatat.c b/system/lib/libc/musl/src/stat/fstatat.c index 631451268c590..6d499c44174a3 100644 --- a/system/lib/libc/musl/src/stat/fstatat.c +++ b/system/lib/libc/musl/src/stat/fstatat.c @@ -145,7 +145,7 @@ static int fstatat_kstat(int fd, const char *restrict path, struct stat *restric int __fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag) { int ret; -#ifdef __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // XXX Emscripten statx syscall unsupported // some logic here copied from fstatat_kstat above if (flag==AT_EMPTY_PATH && fd>=0 && !*path) ret = __syscall(SYS_fstat, fd, st); diff --git a/system/lib/libc/musl/src/stdio/__lockfile.c b/system/lib/libc/musl/src/stdio/__lockfile.c index 2b648c05660a2..01c7ac70ec5f1 100644 --- a/system/lib/libc/musl/src/stdio/__lockfile.c +++ b/system/lib/libc/musl/src/stdio/__lockfile.c @@ -3,7 +3,7 @@ int __lockfile(FILE *f) { -#if defined(__EMSCRIPTEN_PTHREADS__) +#ifdef __EMSCRIPTEN_PTHREADS__ int owner = f->lock, tid = __pthread_self()->tid; if ((owner & ~MAYBE_WAITERS) == tid) return 0; @@ -20,7 +20,7 @@ int __lockfile(FILE *f) void __unlockfile(FILE *f) { -#if defined(__EMSCRIPTEN_PTHREADS__) +#ifdef __EMSCRIPTEN_PTHREADS__ if (a_swap(&f->lock, 0) & MAYBE_WAITERS) __wake(&f->lock, 1, 1); #endif diff --git a/system/lib/libc/musl/src/stdio/__stdio_read.c b/system/lib/libc/musl/src/stdio/__stdio_read.c index 392a4858281f3..c7adefe079f01 100644 --- a/system/lib/libc/musl/src/stdio/__stdio_read.c +++ b/system/lib/libc/musl/src/stdio/__stdio_read.c @@ -8,8 +8,7 @@ size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) { .iov_base = f->buf, .iov_len = f->buf_size } }; ssize_t cnt; - -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ size_t num; if (__wasi_syscall_ret(__wasi_fd_read(f->fd, (struct __wasi_iovec_t*)iov, 2, &num))) { num = -1; diff --git a/system/lib/libc/musl/src/stdio/__stdio_write.c b/system/lib/libc/musl/src/stdio/__stdio_write.c index cce9f6a16a558..097acd53b79cc 100644 --- a/system/lib/libc/musl/src/stdio/__stdio_write.c +++ b/system/lib/libc/musl/src/stdio/__stdio_write.c @@ -12,7 +12,7 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) int iovcnt = 2; ssize_t cnt; for (;;) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ size_t num; if (__wasi_syscall_ret(__wasi_fd_write(f->fd, (struct __wasi_ciovec_t*)iov, iovcnt, &num))) { num = -1; diff --git a/system/lib/libc/musl/src/stdio/stdout.c b/system/lib/libc/musl/src/stdio/stdout.c index 62cf40220a5c4..5054e5b6ccc14 100644 --- a/system/lib/libc/musl/src/stdio/stdout.c +++ b/system/lib/libc/musl/src/stdio/stdout.c @@ -1,6 +1,6 @@ #include "stdio_impl.h" -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // Emscripten doesn't support terminal seeking. static off_t __emscripten_stdout_seek(FILE *f, off_t off, int whence) { @@ -23,7 +23,7 @@ hidden FILE __stdout_FILE = { .fd = 1, .flags = F_PERM | F_NORD, .lbf = '\n', -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // avoid stout_write which adds special terminal window size handling, which emscripten doesn't support anyhow .write = __stdio_write, .seek = __emscripten_stdout_seek, diff --git a/system/lib/libc/musl/src/stdio/vfprintf.c b/system/lib/libc/musl/src/stdio/vfprintf.c index c0542b599024c..ce1acf9140e48 100644 --- a/system/lib/libc/musl/src/stdio/vfprintf.c +++ b/system/lib/libc/musl/src/stdio/vfprintf.c @@ -147,7 +147,7 @@ typedef void (*pop_arg_long_double_t)(union arg *arg, va_list *ap); static void pop_arg_long_double(union arg *arg, va_list *ap) { - arg->f = va_arg(*ap, long double); + arg->f = va_arg(*ap, long double); } static void pop_arg(union arg *arg, int type, va_list *ap, pop_arg_long_double_t pop_arg_long_double) diff --git a/system/lib/libc/musl/src/string/memcmp.c b/system/lib/libc/musl/src/string/memcmp.c index c93cf8cc97330..ba9ab6d41d3c9 100644 --- a/system/lib/libc/musl/src/string/memcmp.c +++ b/system/lib/libc/musl/src/string/memcmp.c @@ -1,4 +1,4 @@ -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #include #endif #include diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index eb1e498b879ca..9b3d0d7fb3a85 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -3,8 +3,7 @@ #include #ifdef __EMSCRIPTEN__ #include -#include -#include +#include // for emscripten_get_now() #else #include "futex.h" #endif @@ -32,10 +31,10 @@ static int __futex4_cp(volatile void *addr, int op, int val, const struct timesp if (r != -ENOSYS) return r; return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to); } -#endif static volatile int dummy = 0; weak_alias(dummy, __eintr_valid_flag); +#endif int __timedwait_cp(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv) @@ -56,7 +55,6 @@ int __timedwait_cp(volatile int *addr, int val, if (to.tv_sec < 0) return ETIMEDOUT; top = &to; } - #ifdef __EMSCRIPTEN__ double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY; int is_runtime_thread = emscripten_is_main_runtime_thread(); @@ -101,11 +99,13 @@ int __timedwait_cp(volatile int *addr, int val, r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top); #endif if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0; +#ifndef __EMSCRIPTEN__ // XXX Emscripten revert musl commit a63c0104e496f7ba78b64be3cd299b41e8cd427f /* Mitigate bug in old kernels wrongly reporting EINTR for non- * interrupting (SA_RESTART) signal handlers. This is only practical * when NO interrupting signal handlers have been installed, and * works by sigaction tracking whether that's the case. */ if (r == EINTR && !__eintr_valid_flag) r = 0; +#endif return r; } diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c b/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c index 232c9b321a8e2..95eefb45ea0a8 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c @@ -77,7 +77,7 @@ int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec #ifndef __EMSCRIPTEN__ if (type&8) return pthread_mutex_timedlock_pi(m, at); #endif - + int spins = 100; while (spins-- && m->_m_lock && !m->_m_waiters) a_spin(); diff --git a/system/lib/libc/musl/src/time/clock_gettime.c b/system/lib/libc/musl/src/time/clock_gettime.c index 18926de8ce8f3..36d901e85dff1 100644 --- a/system/lib/libc/musl/src/time/clock_gettime.c +++ b/system/lib/libc/musl/src/time/clock_gettime.c @@ -56,7 +56,7 @@ static void *volatile vdso_func = (void *)cgt_init; #endif -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ _Static_assert(CLOCK_REALTIME == __WASI_CLOCKID_REALTIME, "monotonic clock must match"); _Static_assert(CLOCK_MONOTONIC == __WASI_CLOCKID_MONOTONIC, "monotonic clock must match"); diff --git a/system/lib/libc/musl/src/time/clock_nanosleep.c b/system/lib/libc/musl/src/time/clock_nanosleep.c index 7ad2aba1a0b7a..3684e43aa14c6 100644 --- a/system/lib/libc/musl/src/time/clock_nanosleep.c +++ b/system/lib/libc/musl/src/time/clock_nanosleep.c @@ -1,7 +1,7 @@ #include #include #include "syscall.h" -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #include #include #endif @@ -12,7 +12,7 @@ int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem) { if (clk == CLOCK_THREAD_CPUTIME_ID) return EINVAL; -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ if (!req || req->tv_nsec < 0 || req->tv_nsec > 999999999L || req->tv_sec < 0) { return EINVAL; } diff --git a/system/lib/libc/musl/src/time/clock_settime.c b/system/lib/libc/musl/src/time/clock_settime.c index ed0182fff664c..686488414371a 100644 --- a/system/lib/libc/musl/src/time/clock_settime.c +++ b/system/lib/libc/musl/src/time/clock_settime.c @@ -1,9 +1,6 @@ #include #include #include "syscall.h" -#ifdef __EMSCRIPTEN__ -#include -#endif #define IS32BIT(x) !((x)+0x80000000ULL>>32) @@ -13,8 +10,7 @@ int clock_settime(clockid_t clk, const struct timespec *ts) // JS and wasm VMs do not allow setting the time. errno = EPERM; return -1; -#else -#ifdef SYS_clock_settime64 +#elif defined(SYS_clock_settime64) // XXX EMSCRIPTEN replace #ifdef SYS_clock_settime64 time_t s = ts->tv_sec; long ns = ts->tv_nsec; int r = -ENOSYS; @@ -29,5 +25,4 @@ int clock_settime(clockid_t clk, const struct timespec *ts) #else return syscall(SYS_clock_settime, clk, ts); #endif -#endif } diff --git a/system/lib/libc/musl/src/unistd/fchdir.c b/system/lib/libc/musl/src/unistd/fchdir.c index bcbd0fc9cc9cd..a22f5f4fed65d 100644 --- a/system/lib/libc/musl/src/unistd/fchdir.c +++ b/system/lib/libc/musl/src/unistd/fchdir.c @@ -9,7 +9,7 @@ int fchdir(int fd) { int ret = __syscall(SYS_fchdir, fd); -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ if (ret != -EBADF || !__wasi_fd_is_valid(fd)) return __syscall_ret(ret); #else diff --git a/system/lib/libc/musl/src/unistd/fchown.c b/system/lib/libc/musl/src/unistd/fchown.c index a328189505444..02facc410b5d1 100644 --- a/system/lib/libc/musl/src/unistd/fchown.c +++ b/system/lib/libc/musl/src/unistd/fchown.c @@ -9,7 +9,7 @@ int fchown(int fd, uid_t uid, gid_t gid) { int ret = __syscall(SYS_fchown, fd, uid, gid); -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ // We can't continue onwards to try the /proc/fd/NNN approach that musl does, // as we don't support that much of POSIX. return __syscall_ret(ret); @@ -24,5 +24,5 @@ int fchown(int fd, uid_t uid, gid_t gid) #else return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid, 0); #endif -#endif // EMSCRIPTEN +#endif // __EMSCRIPTEN__ } diff --git a/system/lib/libc/musl/src/unistd/fsync.c b/system/lib/libc/musl/src/unistd/fsync.c index 2b26be534e96c..8c6c1d13dcc5d 100644 --- a/system/lib/libc/musl/src/unistd/fsync.c +++ b/system/lib/libc/musl/src/unistd/fsync.c @@ -3,7 +3,7 @@ int fsync(int fd) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ return __wasi_syscall_ret(__wasi_fd_sync(fd)); #else return syscall_cp(SYS_fsync, fd); diff --git a/system/lib/libc/musl/src/unistd/pread.c b/system/lib/libc/musl/src/unistd/pread.c index a2361a0473b51..7b790d47d1abc 100644 --- a/system/lib/libc/musl/src/unistd/pread.c +++ b/system/lib/libc/musl/src/unistd/pread.c @@ -3,7 +3,7 @@ ssize_t pread(int fd, void *buf, size_t size, off_t ofs) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ __wasi_iovec_t iov = { .buf = buf, .buf_len = size diff --git a/system/lib/libc/musl/src/unistd/preadv.c b/system/lib/libc/musl/src/unistd/preadv.c index fa6b78c101b3f..5c86d09cf2c7d 100644 --- a/system/lib/libc/musl/src/unistd/preadv.c +++ b/system/lib/libc/musl/src/unistd/preadv.c @@ -5,7 +5,7 @@ ssize_t preadv(int fd, const struct iovec *iov, int count, off_t ofs) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ size_t num; if (__wasi_syscall_ret(__wasi_fd_pread(fd, (struct __wasi_iovec_t*)iov, count, ofs, &num))) { return -1; diff --git a/system/lib/libc/musl/src/unistd/pwrite.c b/system/lib/libc/musl/src/unistd/pwrite.c index 3573ab3902f82..671d7732abd1a 100644 --- a/system/lib/libc/musl/src/unistd/pwrite.c +++ b/system/lib/libc/musl/src/unistd/pwrite.c @@ -3,7 +3,7 @@ ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ __wasi_ciovec_t iov = { .buf = buf, .buf_len = size diff --git a/system/lib/libc/musl/src/unistd/pwritev.c b/system/lib/libc/musl/src/unistd/pwritev.c index bb44236c51ef7..b2d9d7c541f23 100644 --- a/system/lib/libc/musl/src/unistd/pwritev.c +++ b/system/lib/libc/musl/src/unistd/pwritev.c @@ -5,7 +5,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ size_t num; if (__wasi_syscall_ret(__wasi_fd_pwrite(fd, (struct __wasi_ciovec_t*)iov, count, ofs, &num))) { return -1; diff --git a/system/lib/libc/musl/src/unistd/read.c b/system/lib/libc/musl/src/unistd/read.c index f079439c9d302..f84e9436c7c8b 100644 --- a/system/lib/libc/musl/src/unistd/read.c +++ b/system/lib/libc/musl/src/unistd/read.c @@ -3,7 +3,7 @@ ssize_t read(int fd, void *buf, size_t count) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ __wasi_iovec_t iov = { .buf = buf, .buf_len = count diff --git a/system/lib/libc/musl/src/unistd/readv.c b/system/lib/libc/musl/src/unistd/readv.c index bb0760da6e147..3a40c1e9626f6 100644 --- a/system/lib/libc/musl/src/unistd/readv.c +++ b/system/lib/libc/musl/src/unistd/readv.c @@ -3,7 +3,7 @@ ssize_t readv(int fd, const struct iovec *iov, int count) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ size_t num; if (__wasi_syscall_ret(__wasi_fd_read(fd, (struct __wasi_iovec_t*)iov, count, &num))) { num = -1; diff --git a/system/lib/libc/musl/src/unistd/write.c b/system/lib/libc/musl/src/unistd/write.c index 53742cd4fd972..135229be89121 100644 --- a/system/lib/libc/musl/src/unistd/write.c +++ b/system/lib/libc/musl/src/unistd/write.c @@ -3,7 +3,7 @@ ssize_t write(int fd, const void *buf, size_t count) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ __wasi_ciovec_t iov = { .buf = buf, .buf_len = count diff --git a/system/lib/libc/musl/src/unistd/writev.c b/system/lib/libc/musl/src/unistd/writev.c index 443d14f35d1be..4e81f107f61fb 100644 --- a/system/lib/libc/musl/src/unistd/writev.c +++ b/system/lib/libc/musl/src/unistd/writev.c @@ -1,12 +1,12 @@ #include #include "syscall.h" -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ #include #endif ssize_t writev(int fd, const struct iovec *iov, int count) { -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ size_t num; if (__wasi_syscall_ret(__wasi_fd_write(fd, (struct __wasi_ciovec_t*)iov, count, &num))) { return -1; From 4fbbc741fce59cbb397989de5ef54a0565db702e Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 7 Dec 2020 12:27:44 +0100 Subject: [PATCH 02/12] Reapply emscripten libc include changes --- system/lib/libc/musl/include/unistd.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/system/lib/libc/musl/include/unistd.h b/system/lib/libc/musl/include/unistd.h index 73a075c24dd47..388d17bdab7fc 100644 --- a/system/lib/libc/musl/include/unistd.h +++ b/system/lib/libc/musl/include/unistd.h @@ -240,20 +240,20 @@ pid_t gettid(void); #define _POSIX_NO_TRUNC 1 #define _POSIX_RAW_SOCKETS _POSIX_VERSION -#ifndef __EMSCRIPTEN__ -#define _POSIX_REALTIME_SIGNALS _POSIX_VERSION -#else +#ifdef __EMSCRIPTEN__ #define _POSIX_REALTIME_SIGNALS -1 +#else +#define _POSIX_REALTIME_SIGNALS _POSIX_VERSION #endif #define _POSIX_REGEXP 1 #define _POSIX_SAVED_IDS 1 #define _POSIX_SHELL 1 -#ifndef __EMSCRIPTEN__ -#define _POSIX_SPAWN _POSIX_VERSION -#else +#ifdef __EMSCRIPTEN__ #define _POSIX_SPAWN -1 +#else +#define _POSIX_SPAWN _POSIX_VERSION #endif #define _POSIX_VDISABLE 0 From 4fdd54b3485c3d0b1062d4f79b8836d8f5759a7f Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 7 Dec 2020 13:16:13 +0100 Subject: [PATCH 03/12] Reapply arch/emscripten/bits changes --- system/lib/libc/musl/arch/emscripten/bits/limits.h | 4 +++- system/lib/libc/musl/arch/generic/bits/ipc.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/system/lib/libc/musl/arch/emscripten/bits/limits.h b/system/lib/libc/musl/arch/emscripten/bits/limits.h index 7a09fdc1d175d..b36e964152ea1 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/limits.h +++ b/system/lib/libc/musl/arch/emscripten/bits/limits.h @@ -1 +1,3 @@ -#define PAGE_SIZE 65536 +// A value used historically in Emscripten, and which we don't have a strong +// reason to change so far. +#define PAGESIZE 65536 diff --git a/system/lib/libc/musl/arch/generic/bits/ipc.h b/system/lib/libc/musl/arch/generic/bits/ipc.h index 40d6f3a2587cf..779c42fd7bf52 100644 --- a/system/lib/libc/musl/arch/generic/bits/ipc.h +++ b/system/lib/libc/musl/arch/generic/bits/ipc.h @@ -9,3 +9,5 @@ struct ipc_perm { long __pad1; long __pad2; }; + +#define IPC_64 0x100 From 0e2b32720d3f3301c04e93253c484b4abce7b637 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 11 Dec 2020 13:06:02 +0100 Subject: [PATCH 04/12] Deduplicate arch/emscripten/bits directory --- .../lib/libc/musl/arch/emscripten/bits/fenv.h | 18 +----- .../lib/libc/musl/arch/emscripten/bits/mman.h | 4 ++ .../libc/musl/arch/emscripten/bits/posix.h | 7 +++ .../libc/musl/arch/emscripten/bits/setjmp.h | 1 + .../libc/musl/arch/emscripten/bits/signal.h | 58 +++++++++++++------ .../lib/libc/musl/arch/emscripten/bits/stat.h | 12 +++- .../libc/musl/arch/emscripten/bits/stdint.h | 13 ----- .../lib/libc/musl/arch/emscripten/bits/user.h | 48 --------------- 8 files changed, 61 insertions(+), 100 deletions(-) create mode 100644 system/lib/libc/musl/arch/emscripten/bits/mman.h diff --git a/system/lib/libc/musl/arch/emscripten/bits/fenv.h b/system/lib/libc/musl/arch/emscripten/bits/fenv.h index d3512cb6f7f53..96b60ee219548 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/fenv.h +++ b/system/lib/libc/musl/arch/emscripten/bits/fenv.h @@ -6,22 +6,6 @@ #define FE_TOWARDZERO 0xc00 typedef unsigned short fexcept_t; - -typedef struct { - unsigned short __control_word; - unsigned short __unused1; - unsigned short __status_word; - unsigned short __unused2; - unsigned short __tags; - unsigned short __unused3; - unsigned int __eip; - unsigned short __cs_selector; - unsigned int __opcode:11; - unsigned int __unused4:5; - unsigned int __data_offset; - unsigned short __data_selector; - unsigned short __unused5; - unsigned int __mxcsr; -} fenv_t; +typedef unsigned short fenv_t; #define FE_DFL_ENV ((const fenv_t *) -1) diff --git a/system/lib/libc/musl/arch/emscripten/bits/mman.h b/system/lib/libc/musl/arch/emscripten/bits/mman.h new file mode 100644 index 0000000000000..c52e718d0623f --- /dev/null +++ b/system/lib/libc/musl/arch/emscripten/bits/mman.h @@ -0,0 +1,4 @@ +// XXX Emscripten in sync with both: +// - musl/arch/x86_64/bits/mman.h +// - musl/arch/i386/bits/mman.h +#define MAP_32BIT 0x40 diff --git a/system/lib/libc/musl/arch/emscripten/bits/posix.h b/system/lib/libc/musl/arch/emscripten/bits/posix.h index 30a38714f36dd..0dd953c3223f5 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/posix.h +++ b/system/lib/libc/musl/arch/emscripten/bits/posix.h @@ -1,2 +1,9 @@ +#ifdef __wasm64__ +// 64-bit wide pointers under wasm64 +#define _POSIX_V6_LP64_OFF64 1 +#define _POSIX_V7_LP64_OFF64 1 +#else +// 32-bit wide pointers under wasm32 #define _POSIX_V6_ILP32_OFFBIG 1 #define _POSIX_V7_ILP32_OFFBIG 1 +#endif diff --git a/system/lib/libc/musl/arch/emscripten/bits/setjmp.h b/system/lib/libc/musl/arch/emscripten/bits/setjmp.h index decd26dca07a0..1c9aa40ed60c4 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/setjmp.h +++ b/system/lib/libc/musl/arch/emscripten/bits/setjmp.h @@ -1 +1,2 @@ +// XXX Emscripten in sync with musl/arch/i386/bits/setjmp.h typedef unsigned long __jmp_buf[6]; diff --git a/system/lib/libc/musl/arch/emscripten/bits/signal.h b/system/lib/libc/musl/arch/emscripten/bits/signal.h index 58bc5e2c3a780..0c989dfdb9ef9 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/signal.h +++ b/system/lib/libc/musl/arch/emscripten/bits/signal.h @@ -1,3 +1,4 @@ +// XXX Emscripten in sync with musl/arch/i386/bits/signal.h #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) @@ -7,25 +8,44 @@ #endif #ifdef _GNU_SOURCE -#define REG_GS 0 -#define REG_FS 1 -#define REG_ES 2 -#define REG_DS 3 -#define REG_EDI 4 -#define REG_ESI 5 -#define REG_EBP 6 -#define REG_ESP 7 -#define REG_EBX 8 -#define REG_EDX 9 -#define REG_ECX 10 -#define REG_EAX 11 -#define REG_TRAPNO 12 -#define REG_ERR 13 -#define REG_EIP 14 -#define REG_CS 15 -#define REG_EFL 16 -#define REG_UESP 17 -#define REG_SS 18 +enum { REG_GS = 0 }; +#define REG_GS REG_GS +enum { REG_FS = 1 }; +#define REG_FS REG_FS +enum { REG_ES = 2 }; +#define REG_ES REG_ES +enum { REG_DS = 3 }; +#define REG_DS REG_DS +enum { REG_EDI = 4 }; +#define REG_EDI REG_EDI +enum { REG_ESI = 5 }; +#define REG_ESI REG_ESI +enum { REG_EBP = 6 }; +#define REG_EBP REG_EBP +enum { REG_ESP = 7 }; +#define REG_ESP REG_ESP +enum { REG_EBX = 8 }; +#define REG_EBX REG_EBX +enum { REG_EDX = 9 }; +#define REG_EDX REG_EDX +enum { REG_ECX = 10 }; +#define REG_ECX REG_ECX +enum { REG_EAX = 11 }; +#define REG_EAX REG_EAX +enum { REG_TRAPNO = 12 }; +#define REG_TRAPNO REG_TRAPNO +enum { REG_ERR = 13 }; +#define REG_ERR REG_ERR +enum { REG_EIP = 14 }; +#define REG_EIP REG_EIP +enum { REG_CS = 15 }; +#define REG_CS REG_CS +enum { REG_EFL = 16 }; +#define REG_EFL REG_EFL +enum { REG_UESP = 17 }; +#define REG_UESP REG_UESP +enum { REG_SS = 18 }; +#define REG_SS REG_SS #endif struct sigaltstack { diff --git a/system/lib/libc/musl/arch/emscripten/bits/stat.h b/system/lib/libc/musl/arch/emscripten/bits/stat.h index bfa9a597bcf6d..d0259d1483089 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/stat.h +++ b/system/lib/libc/musl/arch/emscripten/bits/stat.h @@ -1,8 +1,8 @@ +// XXX Emscripten in sync with musl/arch/i386/bits/stat.h except for the padding and 64-bit time_t redirections change. + /* copied from kernel definition, but with padding replaced * by the corresponding correctly-sized userspace types. */ - -struct stat -{ +struct stat { dev_t st_dev; #ifndef __EMSCRIPTEN__ int __st_dev_padding; @@ -19,6 +19,12 @@ struct stat off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; +#ifndef __EMSCRIPTEN__ // XXX Emscripten no need to activate the symbol redirections for 64-bit time_t. + struct { + long tv_sec; + long tv_nsec; + } __st_atim32, __st_mtim32, __st_ctim32; +#endif struct timespec st_atim; struct timespec st_mtim; struct timespec st_ctim; diff --git a/system/lib/libc/musl/arch/emscripten/bits/stdint.h b/system/lib/libc/musl/arch/emscripten/bits/stdint.h index 832dca5fb95da..af54a204419d3 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/stdint.h +++ b/system/lib/libc/musl/arch/emscripten/bits/stdint.h @@ -12,22 +12,9 @@ typedef uint32_t uint_fast32_t; #define UINT_FAST16_MAX UINT32_MAX #define UINT_FAST32_MAX UINT32_MAX -#if __LP64__ - -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX -#define PTRDIFF_MIN INT64_MIN -#define PTRDIFF_MAX INT64_MAX -#define SIZE_MAX UINT64_MAX - -#else - #define INTPTR_MIN (-1-__INTPTR_MAX__) #define INTPTR_MAX __INTPTR_MAX__ #define UINTPTR_MAX __UINTPTR_MAX__ #define PTRDIFF_MIN (-1-__PTRDIFF_MAX__) #define PTRDIFF_MAX __PTRDIFF_MAX__ #define SIZE_MAX __SIZE_MAX__ - -#endif diff --git a/system/lib/libc/musl/arch/emscripten/bits/user.h b/system/lib/libc/musl/arch/emscripten/bits/user.h index fa623621eeba3..e69de29bb2d1d 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/user.h +++ b/system/lib/libc/musl/arch/emscripten/bits/user.h @@ -1,48 +0,0 @@ -#undef __WORDSIZE -#define __WORDSIZE 32 - -typedef struct user_fpregs_struct -{ - long cwd, swd, twd, fip, fcs, foo, fos, st_space[20]; -} elf_fpregset_t; - -typedef struct user_fpxregs_struct -{ - unsigned short cwd, swd, twd, fop; - long fip, fcs, foo, fos, mxcsr, reserved; - long st_space[32], xmm_space[32], padding[56]; -} elf_fpxregset_t; - -struct user_regs_struct -{ - long ebx, ecx, edx, esi, edi, ebp, eax, xds, xes, xfs, xgs; - long orig_eax, eip, xcs, eflags, esp, xss; -}; - -#define ELF_NGREG 17 -typedef unsigned long elf_greg_t, elf_gregset_t[ELF_NGREG]; - -struct user -{ - struct user_regs_struct regs; - int u_fpvalid; - struct user_fpregs_struct i387; - unsigned long u_tsize; - unsigned long u_dsize; - unsigned long u_ssize; - unsigned long start_code; - unsigned long start_stack; - long signal; - int reserved; - struct user_regs_struct *u_ar0; - struct user_fpregs_struct *u_fpstate; - unsigned long magic; - char u_comm[32]; - int u_debugreg[8]; -}; - -#define PAGE_MASK (~(PAGE_SIZE-1)) -#define NBPG PAGE_SIZE -#define UPAGES 1 -#define HOST_TEXT_START_ADDR (u.start_code) -#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) From c86be5327e771c2610eaf4f3deb251989e596384 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 19 Nov 2021 12:46:47 +0100 Subject: [PATCH 05/12] Cherry-pick remainder of PR 15739 --- system/lib/libc/musl/src/thread/__timedwait.c | 11 ++++---- system/lib/libc/musl/src/thread/__wait.c | 5 ++-- system/lib/pthread/proxying_legacy.c | 27 ++++++++----------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index 9b3d0d7fb3a85..a7e7ddd1a848d 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -56,21 +56,22 @@ int __timedwait_cp(volatile int *addr, int val, top = &to; } #ifdef __EMSCRIPTEN__ - double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY; + pthread_t self = __pthread_self(); + double msecsToSleep = top ? (top->tv_sec * 1000.0 + top->tv_nsec / 1000000.0) : INFINITY; int is_runtime_thread = emscripten_is_main_runtime_thread(); // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. double max_ms_slice_to_sleep = is_runtime_thread ? 1 : 100; // cp suffix in the function name means "cancellation point", so this wait can be cancelled - // by the users unless current threads cancelability is set to PTHREAD_CANCEL_DISABLE + // by the users unless current threads cancellability is set to PTHREAD_CANCEL_DISABLE // which may be either done by the user of __timedwait() function. if (is_runtime_thread || - pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE || - pthread_self()->cancelasync) { + self->canceldisable != PTHREAD_CANCEL_DISABLE || + self->cancelasync) { double sleepUntilTime = emscripten_get_now() + msecsToSleep; do { - if (pthread_self()->cancel) { + if (self->cancel) { // The thread was canceled by pthread_cancel(). // In the case of cancelasync or PTHREAD_CANCEL_ENABLE we can just call // __pthread_testcancel(), which won't return at all. diff --git a/system/lib/libc/musl/src/thread/__wait.c b/system/lib/libc/musl/src/thread/__wait.c index 5351eeca92b35..3cfcce6300229 100644 --- a/system/lib/libc/musl/src/thread/__wait.c +++ b/system/lib/libc/musl/src/thread/__wait.c @@ -15,16 +15,17 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) } if (waiters) a_inc(waiters); #ifdef __EMSCRIPTEN__ + pthread_t self = __pthread_self(); int is_runtime_thread = emscripten_is_main_runtime_thread(); // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. double max_ms_slice_to_sleep = is_runtime_thread ? 1 : 100; while (*addr==val) { - if (is_runtime_thread || pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) { + if (is_runtime_thread || self->cancelasync) { int e; do { - if (pthread_self()->cancel) { + if (self->cancel) { if (waiters) a_dec(waiters); return; } diff --git a/system/lib/pthread/proxying_legacy.c b/system/lib/pthread/proxying_legacy.c index 246ec2b9e3f97..06dc87ea4495a 100644 --- a/system/lib/pthread/proxying_legacy.c +++ b/system/lib/pthread/proxying_legacy.c @@ -526,24 +526,19 @@ em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_( } EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) { + emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY); + int r; + double target = emscripten_get_now() + timeoutMSecs; + do { + r = -emscripten_futex_wait(&call->operationDone, 0, timeoutMSecs); - int done = atomic_load(&call->operationDone); - if (!done) { - double now = emscripten_get_now(); - double waitEndTime = now + timeoutMSecs; - emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY); - while (!done && now < waitEndTime) { - r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now); - done = atomic_load(&call->operationDone); - now = emscripten_get_now(); - } - emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING); - } - if (done) - return EMSCRIPTEN_RESULT_SUCCESS; - else - return EMSCRIPTEN_RESULT_TIMED_OUT; + timeoutMSecs = target - emscripten_get_now(); + } while (r == ETIMEDOUT && timeoutMSecs > 0); + + emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING); + + return r == ETIMEDOUT ? EMSCRIPTEN_RESULT_TIMED_OUT : EMSCRIPTEN_RESULT_SUCCESS; } EMSCRIPTEN_RESULT emscripten_wait_for_call_i( From c8ee3999a71ccfc40114c86dbc011c58d0442092 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 19 Nov 2021 12:53:40 +0100 Subject: [PATCH 06/12] Minor cleanups --- src/struct_info_internal.json | 6 ++--- .../lib/libc/musl/src/internal/pthread_impl.h | 11 +++++--- system/lib/libc/musl/src/thread/__timedwait.c | 5 ++-- system/lib/libc/musl/src/thread/__wait.c | 7 ++--- .../musl/src/thread/pthread_barrier_wait.c | 4 --- .../lib/libc/musl/src/thread/pthread_detach.c | 3 ++- .../libc/musl/src/thread/pthread_key_create.c | 4 --- system/lib/libc/musl/src/thread/thrd_create.c | 2 -- system/lib/pthread/library_pthread.c | 27 ++++++------------- system/lib/pthread/pthread_create.c | 15 +++++------ system/lib/pthread/threading_internal.h | 2 +- test/pthread/main_thread_join.cpp | 2 +- test/test_posixtest.py | 18 +++++++++++++ 13 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/struct_info_internal.json b/src/struct_info_internal.json index de57123782d4f..f064f1ed7e2c2 100644 --- a/src/struct_info_internal.json +++ b/src/struct_info_internal.json @@ -15,9 +15,9 @@ "_a_transferredcanvases" ], "thread_profiler_block": [ - "threadStatus", - "timeSpentInStatus", - "name" + "threadStatus", + "timeSpentInStatus", + "name" ] }, "defines": [ diff --git a/system/lib/libc/musl/src/internal/pthread_impl.h b/system/lib/libc/musl/src/internal/pthread_impl.h index 22e944a39b846..4da10be8f93f8 100644 --- a/system/lib/libc/musl/src/internal/pthread_impl.h +++ b/system/lib/libc/musl/src/internal/pthread_impl.h @@ -13,9 +13,11 @@ #include "em_task_queue.h" #include "thread_mailbox.h" #include "threading_internal.h" +#include #include -#endif +#else #include "futex.h" +#endif #include "pthread_arch.h" @@ -220,11 +222,12 @@ hidden int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec 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 __EMSCRIPTEN__ - emscripten_futex_wake(addr, cnt); + (void)priv; + emscripten_futex_wake(addr, cnt < 0 ? INT_MAX : cnt); #else + if (priv) priv = FUTEX_PRIVATE; + if (cnt<0) cnt = INT_MAX; __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); #endif diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index a7e7ddd1a848d..6889fb3e08159 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -2,12 +2,11 @@ #include #include #ifdef __EMSCRIPTEN__ -#include #include // for emscripten_get_now() #else #include "futex.h" -#endif #include "syscall.h" +#endif #include "pthread_impl.h" #ifndef __EMSCRIPTEN__ @@ -42,7 +41,9 @@ int __timedwait_cp(volatile int *addr, int val, int r; struct timespec to, *top=0; +#ifndef __EMSCRIPTEN__ if (priv) priv = FUTEX_PRIVATE; +#endif if (at) { if (at->tv_nsec >= 1000000000UL) return EINVAL; diff --git a/system/lib/libc/musl/src/thread/__wait.c b/system/lib/libc/musl/src/thread/__wait.c index 3cfcce6300229..205a08272969e 100644 --- a/system/lib/libc/musl/src/thread/__wait.c +++ b/system/lib/libc/musl/src/thread/__wait.c @@ -1,14 +1,11 @@ -#ifdef __EMSCRIPTEN__ -#include -#include -#endif - #include "pthread_impl.h" void __wait(volatile int *addr, volatile int *waiters, int val, int priv) { int spins=100; +#ifndef __EMSCRIPTEN__ if (priv) priv = FUTEX_PRIVATE; +#endif while (spins-- && (!waiters || !*waiters)) { if (*addr==val) a_spin(); else return; diff --git a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c index 36add3a716936..ad4b432253720 100644 --- a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c +++ b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c @@ -1,7 +1,3 @@ -#ifdef __EMSCRIPTEN__ -#include -#endif - #include "pthread_impl.h" static int pshared_barrier_wait(pthread_barrier_t *b) diff --git a/system/lib/libc/musl/src/thread/pthread_detach.c b/system/lib/libc/musl/src/thread/pthread_detach.c index c25882cca4ac1..2b516e232db06 100644 --- a/system/lib/libc/musl/src/thread/pthread_detach.c +++ b/system/lib/libc/musl/src/thread/pthread_detach.c @@ -32,5 +32,6 @@ static int __pthread_detach(pthread_t t) weak_alias(__pthread_detach, pthread_detach); weak_alias(__pthread_detach, thrd_detach); -// XXX EMSCRIPTEN: add extra alias for asan. +#ifdef __EMSCRIPTEN__ // XXX Emscripten add an extra alias for ASan/LSan. weak_alias(__pthread_detach, emscripten_builtin_pthread_detach); +#endif diff --git a/system/lib/libc/musl/src/thread/pthread_key_create.c b/system/lib/libc/musl/src/thread/pthread_key_create.c index f45553919647a..39770c7a3c829 100644 --- a/system/lib/libc/musl/src/thread/pthread_key_create.c +++ b/system/lib/libc/musl/src/thread/pthread_key_create.c @@ -1,10 +1,6 @@ #include "pthread_impl.h" #include "fork_impl.h" -#ifdef __EMSCRIPTEN__ -#include -#endif - volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 }; diff --git a/system/lib/libc/musl/src/thread/thrd_create.c b/system/lib/libc/musl/src/thread/thrd_create.c index ca4efb661973b..d1191660a292d 100644 --- a/system/lib/libc/musl/src/thread/thrd_create.c +++ b/system/lib/libc/musl/src/thread/thrd_create.c @@ -6,8 +6,6 @@ // if we call the internal __pthread_create function here to don't the wrapping // See pthread_create wrapper in compiler-rt/lib/lsan/lsan_interceptors.cpp. #define __pthread_create pthread_create -#else -int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict); #endif int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index cd0c0ba1a71ad..5e54831e6affd 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -5,27 +5,15 @@ * found in the LICENSE file. */ -#define _GNU_SOURCE -#include "../internal/libc.h" -#include "../internal/pthread_impl.h" +#include "libc.h" +#include "pthread_impl.h" #include -#include -#include -#include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include -#include #include #include @@ -142,16 +130,17 @@ void _emscripten_init_main_thread(void) { // a magic ID to detect whether the pthread_t structure is 'alive'. __main_pthread.self = &__main_pthread; __main_pthread.detach_state = DT_JOINABLE; - // pthread struct robust_list head should point to itself. - __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // Main thread ID is always 1. It can't be 0 because musl assumes // tid is always non-zero. __main_pthread.tid = getpid(); __main_pthread.locale = &libc.global_locale; + // Initialize thread-specific data area. + __main_pthread.tsd = (void **)__pthread_tsd_main; + // pthread struct robust_list head should point to itself. + __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // pthread struct prev and next should initially point to itself (see __init_tp), // this is used by pthread_key_delete for deleting thread-specific data. __main_pthread.next = __main_pthread.prev = &__main_pthread; - __main_pthread.tsd = (void **)__pthread_tsd_main; _emscripten_init_main_thread_js(&__main_pthread); diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index d92c35bf15a28..b8da943536b31 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#define _GNU_SOURCE #include "pthread_impl.h" #include "stdio_impl.h" #include "assert.h" @@ -115,7 +114,7 @@ int __pthread_create(pthread_t* restrict res, void* (*entry)(void*), void* restrict arg) { // Note on LSAN: lsan intercepts/wraps calls to pthread_create so any - // allocation we we do here should be considered leaks. + // allocation we do here should be considered as leak. // See: lsan_interceptors.cpp. if (!res) { return EINVAL; @@ -297,11 +296,11 @@ void _emscripten_thread_free_data(pthread_t t) { } void _emscripten_thread_exit(void* result) { - struct pthread *self = __pthread_self(); + pthread_t self = __pthread_self(); assert(self); - self->canceldisable = PTHREAD_CANCEL_DISABLE; - self->cancelasync = PTHREAD_CANCEL_DEFERRED; + self->canceldisable = 1; + self->cancelasync = 0; self->result = result; _emscripten_thread_mailbox_shutdown(self); @@ -349,8 +348,8 @@ void _emscripten_thread_exit(void* result) { // Not hosting a pthread anymore in this worker set __pthread_self to NULL __set_thread_state(NULL, 0, 0, 1); - /* This atomic potentially competes with a concurrent pthread_detach - * call; the loser is responsible for freeing thread resources. */ + // This atomic potentially competes with a concurrent pthread_detach + // call; the loser is responsible for freeing thread resources. int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING); if (state == DT_DETACHED) { @@ -368,7 +367,7 @@ void _emscripten_thread_exit(void* result) { } } -// Mark as `no_sanitize("address"` since emscripten_pthread_exit destroys +// Mark as `no_sanitize("address")` since emscripten_pthread_exit destroys // the current thread and runs its exit handlers. Without this asan injects // a call to __asan_handle_no_return before emscripten_unwind_to_js_event_loop // which seem to cause a crash later down the line. diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index eae455944d578..f4cf00581cf8e 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -92,7 +92,7 @@ void emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS expectedS #endif int __pthread_kill_js(pthread_t t, int sig); -int __pthread_create_js(struct __pthread *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); +int __pthread_create_js(pthread_t thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); int _emscripten_default_pthread_stack_size(); void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block); diff --git a/test/pthread/main_thread_join.cpp b/test/pthread/main_thread_join.cpp index afa611aaf7ad5..ece9c74d59920 100644 --- a/test/pthread/main_thread_join.cpp +++ b/test/pthread/main_thread_join.cpp @@ -33,7 +33,7 @@ void *ThreadMain(void *arg) { // succeeding. while (tries.load() < EXPECTED_TRIES) {} #endif - pthread_exit((void*)0); + pthread_exit((void*)0); } pthread_t CreateThread() { diff --git a/test/test_posixtest.py b/test/test_posixtest.py index fc0fe20738898..6d6faef8216f1 100644 --- a/test/test_posixtest.py +++ b/test/test_posixtest.py @@ -7,6 +7,15 @@ ./test/third_party/posixtestsuite See https://github.com/emscripten-core/posixtestsuite + +Verify that it runs properly in musl: + cd tests/third_party/posixtestsuite + docker run -v $(pwd):/app -w /app -it alpine:latest sh -c "\ + apk add build-base && \ + POSIX_TARGET=conformance/interfaces/[INTERFACE_DIR] make LDFLAGS='-pthread' CFLAGS='-D__EMSCRIPTEN__'" + cat logfile + +Where [INTERFACE_DIR] is for e.g.: pthread_detach """ import glob @@ -161,6 +170,15 @@ def f(self): if name in disabled: self.skipTest(disabled[name]) args = ['-I' + os.path.join(testsuite_root, 'include'), + # TODO(kleisauke): Run with ASan. Note that this requires matching signatures, i.e: + # void *thread_func() -> void *thread_func(void *unused) + # void *a_thread_func() -> void *a_thread_func(void *unused) + # void *a_thread_function() -> void *a_thread_function(void *unused) + # void a_cleanup_func() -> void a_cleanup_func(void *unused) + # etc, etc. + # '-O0', + # '-g3', + # '-fsanitize=address', '-Werror', '-Wno-format-security', '-Wno-int-conversion', From abe68976532d7e562f6ceb92a476d4fd17f5c00e Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Thu, 18 Feb 2021 14:17:47 +0100 Subject: [PATCH 07/12] Move pthread_barrier_wait logic to __futexwait. NFC --- .../lib/libc/musl/src/internal/pthread_impl.h | 13 ++++++++++++- .../musl/src/thread/pthread_barrier_wait.c | 18 +++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/system/lib/libc/musl/src/internal/pthread_impl.h b/system/lib/libc/musl/src/internal/pthread_impl.h index 4da10be8f93f8..39dc65da0e0ed 100644 --- a/system/lib/libc/musl/src/internal/pthread_impl.h +++ b/system/lib/libc/musl/src/internal/pthread_impl.h @@ -235,7 +235,18 @@ static inline void __wake(volatile void *addr, int cnt, int priv) static inline void __futexwait(volatile void *addr, int val, int priv) { #ifdef __EMSCRIPTEN__ - __wait(addr, NULL, val, priv); + (void)priv; + const int is_runtime_thread = emscripten_is_main_runtime_thread(); + if (is_runtime_thread) { + int e; + do { + // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. + e = emscripten_futex_wait(addr, val, 1); + } while (e == -ETIMEDOUT); + } else { + // Can wait in one go. + emscripten_futex_wait(addr, val, INFINITY); + } #else if (priv) priv = FUTEX_PRIVATE; __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || diff --git a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c index ad4b432253720..81dfe4093689d 100644 --- a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c +++ b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c @@ -83,26 +83,14 @@ int pthread_barrier_wait(pthread_barrier_t *b) while (spins-- && !inst->finished) a_spin(); a_inc(&inst->finished); -#ifdef __EMSCRIPTEN__ - int is_runtime_thread = emscripten_is_main_runtime_thread(); while (inst->finished == 1) { - if (is_runtime_thread) { - int e; - do { - // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. - e = emscripten_futex_wait(&inst->finished, 1, 1); - } while (e == -ETIMEDOUT); - } else { - // Can wait in one go. - emscripten_futex_wait(&inst->finished, 1, INFINITY); - } - } +#ifdef __EMSCRIPTEN__ + __futexwait(&inst->finished, 1, 1); #else - while (inst->finished == 1) { __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0); - } #endif + } return PTHREAD_BARRIER_SERIAL_THREAD; } From 37928a95558769a9c8692c5aedbfe3c43113f99a Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 27 Feb 2021 14:47:09 +0100 Subject: [PATCH 08/12] Simplify thread clean / exit / terminate logic. NFC Mostly inspired by musl. --- .../lib/libc/musl/src/thread/pthread_detach.c | 31 ++++++++++++------- .../lib/libc/musl/src/thread/pthread_join.c | 7 ++--- system/lib/pthread/library_pthread.c | 5 ++- system/lib/pthread/pthread_create.c | 18 ++++++----- test/other/test_pthread_self_join_detach.c | 14 ++------- 5 files changed, 36 insertions(+), 39 deletions(-) diff --git a/system/lib/libc/musl/src/thread/pthread_detach.c b/system/lib/libc/musl/src/thread/pthread_detach.c index 2b516e232db06..badd8538be37f 100644 --- a/system/lib/libc/musl/src/thread/pthread_detach.c +++ b/system/lib/libc/musl/src/thread/pthread_detach.c @@ -4,30 +4,37 @@ static int __pthread_detach(pthread_t t) { #ifdef __EMSCRIPTEN__ - // XXX EMSCRIPTEN: Add check for invalid (already joined) thread. Again + // XXX Emscripten: Add check for invalid (already joined) thread. Again // for the benefit of the conformance tests. - if (!_emscripten_thread_is_valid(t)) - return ESRCH; -#endif - /* If the cas fails, detach state is either already-detached - * or exiting/exited, and pthread_join will trap or cleanup. */ -#ifdef __EMSCRIPTEN__ - int old_state = a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED); - if (old_state != DT_JOINABLE) { + if (!_emscripten_thread_is_valid(t)) return ESRCH; + + // Note that we don't use pthread_join here, to avoid + // returning EDEADLK when attempting to detach itself. + switch (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED)) { + case DT_EXITED: + case DT_EXITING: + _emscripten_thread_cleanup(t); + return 0; + case DT_JOINABLE: + return 0; + case DT_DETACHED: // already-detached + default: // >= DT_DETACHED // Even though the man page says this is undefined behaviour to attempt to // detach an already-detached thread we have several tests in the posixtest // suite that depend on this (pthread_join.c) - if (old_state == DT_DETACHED) - return EINVAL; + return EINVAL; + } #else + /* If the cas fails, detach state is either already-detached + * or exiting/exited, and pthread_join will trap or cleanup. */ if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) { -#endif int cs; __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); __pthread_join(t, 0); __pthread_setcancelstate(cs, 0); } return 0; +#endif } weak_alias(__pthread_detach, pthread_detach); diff --git a/system/lib/libc/musl/src/thread/pthread_join.c b/system/lib/libc/musl/src/thread/pthread_join.c index a5d539b651754..3526941228fd1 100644 --- a/system/lib/libc/musl/src/thread/pthread_join.c +++ b/system/lib/libc/musl/src/thread/pthread_join.c @@ -13,11 +13,8 @@ static int __pthread_timedjoin_np(pthread_t t, void **res, const struct timespec // Attempt to join a thread which does not point to a valid thread, or // does not exist anymore. if (!_emscripten_thread_is_valid(t)) return ESRCH; - // Thread is attempting to join to itself. Already detached threads are - // handled below by returning EINVAL instead. - // TODO: The detached check here is just to satisfy the - // `other.test_{proxy,main}_pthread_join_detach` tests. - if (t->detach_state != DT_DETACHED && __pthread_self() == t) return EDEADLK; + // Thread is attempting to join to itself. + if (__pthread_self() == t) return EDEADLK; #endif int state, cs, r = 0; __pthread_testcancel(); diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 5e54831e6affd..3bf0c9499e22b 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -117,7 +117,7 @@ void emscripten_main_thread_process_queued_calls() { } int _emscripten_thread_is_valid(pthread_t thread) { - return thread->self == thread; + return thread->tid; } static void *dummy_tsd[1] = { 0 }; @@ -126,8 +126,7 @@ weak_alias(dummy_tsd, __pthread_tsd_main); // See system/lib/README.md for static constructor ordering. __attribute__((constructor(48))) void _emscripten_init_main_thread(void) { - // The pthread struct has a field that points to itself - this is used as - // a magic ID to detect whether the pthread_t structure is 'alive'. + // The pthread struct has a field that points to itself. __main_pthread.self = &__main_pthread; __main_pthread.detach_state = DT_JOINABLE; // Main thread ID is always 1. It can't be 0 because musl assumes diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index b8da943536b31..018f8bab7226f 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -173,9 +173,10 @@ int __pthread_create(pthread_t* restrict res, new->map_base = block; new->map_size = size; - // The pthread struct has a field that points to itself - this is used as a - // magic ID to detect whether the pthread_t structure is 'alive'. + // The pthread struct has a field that points to itself. new->self = new; + + // Thread ID, this becomes zero when the thread is no longer available. new->tid = next_tid++; // pthread struct robust_list head should point to itself. @@ -280,18 +281,21 @@ void _emscripten_thread_free_data(pthread_t t) { // A thread can never free its own thread data. assert(t != pthread_self()); #ifndef NDEBUG - if (t->profilerBlock) { - emscripten_builtin_free(t->profilerBlock); + intptr_t old_block = __c11_atomic_exchange((_Atomic intptr_t*)&t->profilerBlock, 0, __ATOMIC_SEQ_CST); + if (old_block) { + emscripten_builtin_free((void*)old_block); } #endif + // The tid may be reused. Clear it to prevent inadvertent use + // and inform functions that would use it that it's no longer + // available. + t->tid = 0; - // Free all the enture thread block (called map_base because + // Free the entire thread block (called map_base because // musl normally allocates this using mmap). This region // includes the pthread structure itself. unsigned char* block = t->map_base; dbg("_emscripten_thread_free_data thread=%p map_base=%p", t, block); - // To aid in debugging, set the entire region to zero. - memset(block, 0, sizeof(struct pthread)); emscripten_builtin_free(block); } diff --git a/test/other/test_pthread_self_join_detach.c b/test/other/test_pthread_self_join_detach.c index 7d4293b76dfde..2679e5cae9867 100644 --- a/test/other/test_pthread_self_join_detach.c +++ b/test/other/test_pthread_self_join_detach.c @@ -21,17 +21,11 @@ int main() { pthread_t self = pthread_self(); /* - * Attempts to join the current thread will either generate - * EDEADLK or EINVAL depending on whether has already been - * detached + * Attempts to join the current thread will generate EDEADLK. */ int ret = pthread_join(self, NULL); printf("pthread_join -> %s\n", strerror(ret)); - if (is_detached) { - assert(ret == EINVAL); - } else { - assert(ret == EDEADLK); - } + assert(ret == EDEADLK); /* * Attempts to detach the main thread will either succeed @@ -45,10 +39,6 @@ int main() { assert(ret == 0); } - ret = pthread_join(self, NULL); - printf("pthread_join -> %s\n", strerror(ret)); - assert(ret == EINVAL); - puts("passed"); return 0; From e4ae7cd0dd1425ec5e4b1cfbbeee9f984e718062 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 30 Jun 2021 15:10:13 +0200 Subject: [PATCH 09/12] Disable warnings on thread pool exhaustion in posixtest posixtest.test_pthread_cond_broadcast_1_2 seems to trigger this. --- test/test_posixtest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_posixtest.py b/test/test_posixtest.py index 6d6faef8216f1..e880efd1e8e4a 100644 --- a/test/test_posixtest.py +++ b/test/test_posixtest.py @@ -186,7 +186,8 @@ def f(self): '-pthread', '-sEXIT_RUNTIME', '-sTOTAL_MEMORY=256mb', - '-sPTHREAD_POOL_SIZE=40'] + '-sPTHREAD_POOL_SIZE=40', + '-sPTHREAD_POOL_SIZE_STRICT=0'] if browser: self.btest_exit(testfile, args=args) else: From 5cfb4b68f0719b8037ab752fb93d22835f3fa462 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 30 Jun 2021 16:38:31 +0200 Subject: [PATCH 10/12] Minor improvements --- src/lib/libnoderawfs.js | 2 +- src/lib/libwasi.js | 8 ++++---- system/lib/compiler-rt/lib/asan/asan_interceptors.h | 6 +++--- .../compiler-rt/lib/lsan/lsan_common_emscripten.cpp | 4 +++- .../lib/compiler-rt/lib/lsan/lsan_interceptors.cpp | 13 +++++-------- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/lib/libnoderawfs.js b/src/lib/libnoderawfs.js index c7e86e95b1566..875081cf02d6d 100644 --- a/src/lib/libnoderawfs.js +++ b/src/lib/libnoderawfs.js @@ -57,7 +57,7 @@ addToLibrary({ // generic function for all node creation cwd() { return process.cwd(); }, chdir(...args) { process.chdir(...args); }, - mknod(path, mode) { + mknod(path, mode/*, dev */) { if (FS.isDir(path)) { fs.mkdirSync(path, mode); } else { diff --git a/src/lib/libwasi.js b/src/lib/libwasi.js index 2d3b143f0969a..e92112738aaca 100644 --- a/src/lib/libwasi.js +++ b/src/lib/libwasi.js @@ -509,13 +509,13 @@ var WasiLibrary = { var type = stream.tty ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : FS.isDir(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_DIRECTORY }}} : FS.isLink(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_SYMBOLIC_LINK }}} : - {{{ cDefs.__WASI_FILETYPE_REGULAR_FILE }}}; + FS.isFile(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_REGULAR_FILE }}} : + -1; + if (type === -1) return -{{{ cDefs.EBADF }}}; #else // Hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0. We support at // least stdin, stdout, stderr in a simple way. -#if ASSERTIONS - assert(fd == 0 || fd == 1 || fd == 2); -#endif + if (fd < 0 || fd > 2) return -{{{ cDefs.EBADF }}}; var type = {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}}; if (fd == 0) { rightsBase = {{{ cDefs.__WASI_RIGHTS_FD_READ }}}; diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.h b/system/lib/compiler-rt/lib/asan/asan_interceptors.h index 3e2386eaf8092..eee3a7dcd42d6 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors.h +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.h @@ -26,10 +26,10 @@ void InitializePlatformInterceptors(); } // namespace __asan -// There is no general interception at all on Fuchsia. +// There is no general interception at all on Fuchsia and Emscripten. // Only the functions in asan_interceptors_memintrinsics.h are // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN // Use macro to describe if specific function should be // intercepted on a given platform. @@ -162,6 +162,6 @@ DECLARE_REAL(char*, strstr, const char *s1, const char *s2) (void) ctx; #define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN #endif // ASAN_INTERCEPTORS_H diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp index 46bfedb9b519b..d5b16edba4cf1 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp @@ -119,11 +119,12 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback, // Finally, we can only obtain the stack pointer for the current thread, // so we scan the full stack for other threads. static void ProcessThreadsCallback(ThreadContextBase *tctx, void *arg) { + tid_t os_id = tctx->os_id; + LOG_THREADS("Processing thread %llu\n", os_id); if (tctx->status != ThreadStatusRunning) return; Frontier *frontier = reinterpret_cast(arg); - tid_t os_id = tctx->os_id; uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; DTLS *dtls; @@ -154,6 +155,7 @@ static void ProcessThreadsCallback(ThreadContextBase *tctx, void *arg) { } ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", kReachable); + //ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier); } if (flags()->use_tls && tls_begin) { diff --git a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp index 39440768c83c1..9a0596d77d721 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -560,9 +560,8 @@ INTERCEPTOR(void, _exit, int status) { namespace __lsan { void InitializeInterceptors() { - // Fuchsia doesn't use interceptors that require any setup. -#if !SANITIZER_FUCHSIA -#if !SANITIZER_EMSCRIPTEN + // Fuchsia and Emscripten doesn't use interceptors that require any setup. +#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN __interception::DoesNotSupportStaticLinking(); InitializeSignalInterceptors(); @@ -596,17 +595,15 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; LSAN_MAYBE_INTERCEPT_STRERROR; -#endif // !SANITIZER_EMSCRIPTEN +#endif // !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN -#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); Die(); } #endif - -#endif // !SANITIZER_FUCHSIA } } // namespace __lsan -#endif // SANITIZER_EMSCRIPTEN +#endif // SANITIZER_POSIX From ea937cf41f326cb578ebe3c46ac4323e331a5882 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 23 Jul 2021 15:03:04 +0200 Subject: [PATCH 11/12] Remove early return from `exitRuntime()`. NFC `exitRuntime()` is never called when `ENVIRONMENT_IS_PTHREAD` is true. --- src/preamble.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/preamble.js b/src/preamble.js index 6b34051bdef31..06becf1a67f97 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -196,7 +196,6 @@ function exitRuntime() { #if STACK_OVERFLOW_CHECK checkStackCookie(); #endif - {{{ runIfWorkerThread('return;') }}} // PThreads reuse the runtime from the main thread. #if !STANDALONE_WASM ___funcs_on_exit(); // Native atexit() functions #endif From 37e9810c065d4e7f555e36009d957d4d382dd1f2 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 11 Aug 2021 16:43:55 +0200 Subject: [PATCH 12/12] Improve sanitizer detection __has_feature(leak_sanitizer) cannot be used to detect the existence of LSan. --- system/include/emscripten/bind.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 9bceabd53481e..350f29dfc3faa 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -26,7 +26,7 @@ #include #include -#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) +#if defined(HAS_LSAN) || __has_feature(address_sanitizer) #include #endif @@ -747,7 +747,7 @@ template inline T* getContext(const T& t) { // not a leak because this is called once per binding auto* ret = new T(t); -#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) +#if defined(HAS_LSAN) || __has_feature(address_sanitizer) __lsan_ignore_object(ret); #endif return ret;