Port kleisauke's https://github.com/emscripten-core/emscripten/commit/d5d5f69ad066aee2e22a601921411b94206d035d
diff --git a/system/lib/libc/emscripten_pthread.c b/system/lib/libc/emscripten_pthread.c index 9221622..1cf2641 100644 --- a/system/lib/libc/emscripten_pthread.c +++ b/system/lib/libc/emscripten_pthread.c
@@ -1,6 +1,7 @@ #include <pthread.h> #include "libc.h" #include "pthread_impl.h" +#include "stdio_impl.h" #if !__EMSCRIPTEN_PTHREADS__ static struct pthread __main_pthread; @@ -24,6 +25,17 @@ PThread.initRuntime(); }) +static void init_file_lock(FILE *f) +{ + if (f && f->lock<0) f->lock = 0; +} + +// std{in,out,err}.c will override this if linked +static FILE *volatile dummy_file = 0; +weak_alias(dummy_file, __stdin_used); +weak_alias(dummy_file, __stdout_used); +weak_alias(dummy_file, __stderr_used); + // This must run before any userland ctors // Note that ASan constructor priority is 50, and we must be higher. EMSCRIPTEN_KEEPALIVE @@ -31,5 +43,10 @@ void __emscripten_pthread_data_constructor(void) { initPthreadsJS(); pthread_self()->locale = &libc.global_locale; + // Ensure fprintf is thread-safe, see musl commit dba68bf98fc708cea4c478278c889fc7ad802b00 + init_file_lock(__stdin_used); + init_file_lock(__stdout_used); + init_file_lock(__stderr_used); + libc.threaded = 1; } #endif
diff --git a/tests/core/test_printf_thread.c b/tests/core/test_printf_thread.c new file mode 100644 index 0000000..4b9e147 --- /dev/null +++ b/tests/core/test_printf_thread.c
@@ -0,0 +1,45 @@ +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "../../system/lib/libc/musl/include/features.h" +#include "../../system/lib/libc/musl/src/internal/stdio_impl.h" +#include "../../system/lib/libc/musl/src/internal/libc.h" + +pthread_t thread[2]; + +char *char_repeat(int n, char c) { + char *dest = malloc(n + 1); + memset(dest, c, n); + dest[n] = '\0'; + return dest; +} + +void *thread_main(void *arg) { + char *msg = char_repeat(100, 'a'); + for (int i = 0; i < 10; ++i) + printf("%s\n", msg); + free(msg); + return 0; +} + +int main() { + printf("stdin lock: %d\n", stderr->lock); + printf("stdout lock: %d\n", stdin->lock); + printf("stderr lock: %d\n", stderr->lock); + printf("threaded libc: %d\n", libc.threaded); + int rc = pthread_create(&thread[0], NULL, thread_main, NULL); + assert(rc == 0); + rc = pthread_create(&thread[1], NULL, thread_main, NULL); + assert(rc == 0); + void *thread_rtn = 0; + rc = pthread_join(thread[0], &thread_rtn); + assert(rc == 0); + assert(thread_rtn == 0); + rc = pthread_join(thread[1], &thread_rtn); + assert(rc == 0); + assert(thread_rtn == 0); + + return 0; +}
diff --git a/tests/core/test_printf_thread.out b/tests/core/test_printf_thread.out new file mode 100644 index 0000000..10d6ba5 --- /dev/null +++ b/tests/core/test_printf_thread.out
@@ -0,0 +1,24 @@ +stdin lock: 0 +stdout lock: 0 +stderr lock: 0 +threaded libc: 1 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/tests/test_core.py b/tests/test_core.py index a9009b2..c778877 100644 --- a/tests/test_core.py +++ b/tests/test_core.py
@@ -8320,6 +8320,12 @@ self.set_setting('USE_PTHREADS') self.do_run_in_out_file_test('core', 'pthread', 'emscripten_futexes.c') + @node_pthreads + def test_printf_thread(self): + self.set_setting('PTHREAD_POOL_SIZE', '2') + self.set_setting('EXIT_RUNTIME') + self.do_run_in_out_file_test('core', 'test_printf_thread.c') + @needs_dylink @node_pthreads def test_pthread_dylink_basics(self):
diff --git a/tools/system_libs.py b/tools/system_libs.py index 18e993e..27c2e0a 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py
@@ -1223,7 +1223,7 @@ force_object_files = True -class libc_rt_wasm(OptimizedAggressivelyForSizeLibrary, AsanInstrumentedLibrary, CompilerRTLibrary, MuslInternalLibrary): +class libc_rt_wasm(OptimizedAggressivelyForSizeLibrary, AsanInstrumentedLibrary, CompilerRTLibrary, MuslInternalLibrary, MTLibrary): name = 'libc_rt_wasm' def get_files(self):