From f53df1ac31604dc6666ebc3e01391bdc80913ee6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 16 Sep 2021 17:39:05 -0700 Subject: [PATCH] Enable file locking in musl stdio This is a slightly modified version of https://github.com/emscripten-core/emscripten/commit/d5d5f69ad066aee2e22a601921411b94206d035d The change to __lockfile.c means we always compile in the locking code but atomics will get lowered away in single threaded builds and the wait/wake functions are no-ops in this mode too, so it should not effect code size in release builds. Because __lockfile.c is not compiled into a multi-thread-aware library (its not part of an MTLibrary) it was never actually being built with `__EMSCRIPTEN_PTHREADS__`. Fixes: #13194 --- system/lib/libc/musl/src/stdio/__lockfile.c | 4 ---- system/lib/pthread/pthread_create.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/system/lib/libc/musl/src/stdio/__lockfile.c b/system/lib/libc/musl/src/stdio/__lockfile.c index 7932d4a1b204..9d967d6eb886 100644 --- a/system/lib/libc/musl/src/stdio/__lockfile.c +++ b/system/lib/libc/musl/src/stdio/__lockfile.c @@ -3,19 +3,16 @@ int __lockfile(FILE *f) { -#if defined(__EMSCRIPTEN_PTHREADS__) int owner, tid = __pthread_self()->tid; if (f->lock == tid) return 0; while ((owner = a_cas(&f->lock, 0, tid))) __wait(&f->lock, &f->waiters, owner, 1); -#endif return 1; } void __unlockfile(FILE *f) { -#if defined(__EMSCRIPTEN_PTHREADS__) a_store(&f->lock, 0); /* The following read is technically invalid under situations @@ -28,5 +25,4 @@ void __unlockfile(FILE *f) * malloc changes, this assumption needs revisiting. */ if (f->waiters) __wake(&f->lock, 1, 1); -#endif } diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index badbf3f0385f..e277d372970e 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -7,6 +7,7 @@ #define _GNU_SOURCE #include "pthread_impl.h" +#include "stdio_impl.h" #include "assert.h" #include #include @@ -53,6 +54,15 @@ void __do_cleanup_pop(struct __ptcb *cb) { __pthread_self()->cancelbuf = cb->__next; } +static FILE *volatile dummy_file = 0; +weak_alias(dummy_file, __stdin_used); +weak_alias(dummy_file, __stdout_used); +weak_alias(dummy_file, __stderr_used); + +static void init_file_lock(FILE *f) { + if (f && f->lock<0) f->lock = 0; +} + int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, 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. @@ -61,6 +71,17 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att return EINVAL; } + pthread_t self = __pthread_self(); + if (!libc.threaded) { + for (FILE *f=*__ofl_lock(); f; f=f->next) + init_file_lock(f); + __ofl_unlock(); + init_file_lock(__stdin_used); + init_file_lock(__stdout_used); + init_file_lock(__stderr_used); + libc.threaded = 1; + } + // Allocate thread block (pthread_t structure). struct pthread *new = malloc(sizeof(struct pthread)); // zero-initialize thread structure.