Skip to content

Commit 99c6872

Browse files
authored
Avoid allocating TLS for the first thread that loads. NFC (#17018)
This change depend on an LLVM-side change in order to actually do anything: https://reviews.llvm.org/D126107. It can land on its own but won't have any effect since __tls_base will always be zero on startup until that change lands. The linker will load the TLS data into a static location that the loading thread can use directly rather than dynamically allocating it. Secondary threads still require dynamic allocation but I'm hoping to avoid that too (at least for load-time dynamic libraries and especially for the main module). See: #16948
1 parent 72599b8 commit 99c6872

File tree

5 files changed

+50
-19
lines changed

5 files changed

+50
-19
lines changed

src/postamble.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,11 @@ function exit(status, implicit) {
425425
throw 'unwind';
426426
} else {
427427
#if PTHREADS_DEBUG
428+
#if EXIT_RUNTIME
428429
err('main thread called exit: keepRuntimeAlive=' + keepRuntimeAlive() + ' (counter=' + runtimeKeepaliveCounter + ')');
430+
#else
431+
err('main thread called exit: keepRuntimeAlive=' + keepRuntimeAlive());
432+
#endif
429433
#endif
430434
}
431435
}

system/lib/pthread/emscripten_tls_init.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
// Included for emscripten_builtin_free / emscripten_builtin_malloc
99
// TODO(sbc): Should these be in their own header to avoid emmalloc here?
1010
#include <emscripten/emmalloc.h>
11-
#include <pthread.h>
11+
#include <emscripten/threading.h>
12+
13+
#include "pthread_impl.h"
1214

1315
// Uncomment to trace TLS allocations.
1416
// #define DEBUG_TLS
@@ -21,15 +23,49 @@ extern void __wasm_init_tls(void *memory);
2123

2224
extern int __dso_handle;
2325

26+
// Create a thread-local wasm global which signal that the current thread is non
27+
// to use the primary/static TLS region. Once this gets set it forces that all
28+
// future calls to emscripten_tls_init to dynamically allocate TLS.
29+
// This is needed because emscripten re-uses module instances owned by the
30+
// worker for new pthreads. This in turn means that stale values of __tls_base
31+
// from a previous pthreads need to be ignored.
32+
// If this global is true then TLS needs to be dyanically allocated, if its
33+
// flase we are free to use the existing/global __tls_base.
34+
__asm__(".globaltype is_not_primary_tls, i32\n"
35+
"is_not_primary_tls:\n");
36+
37+
static void set_non_primary(void) {
38+
__asm__("i32.const 1\n"
39+
"global.set is_not_primary_tls\n");
40+
}
41+
42+
static int is_non_primary(void) {
43+
int val;
44+
__asm__("global.get is_not_primary_tls\n"
45+
"local.set %0" : "=r" (val));
46+
return val;
47+
}
48+
49+
void emscripten_tls_free() {
50+
void* tls_block = __builtin_wasm_tls_base();
51+
if (tls_block && is_non_primary()) {
52+
#ifdef DEBUG_TLS
53+
printf("tls free: thread=%p dso=%p <- %p\n", pthread_self(), &__dso_handle, tls_block);
54+
#endif
55+
emscripten_builtin_free(tls_block);
56+
}
57+
}
58+
2459
void* emscripten_tls_init(void) {
2560
size_t tls_size = __builtin_wasm_tls_size();
26-
size_t tls_align = __builtin_wasm_tls_align();
27-
if (!tls_size) {
28-
return NULL;
61+
void* tls_block = __builtin_wasm_tls_base();
62+
if (is_non_primary() || (!tls_block && tls_size)) {
63+
set_non_primary();
64+
size_t tls_align = __builtin_wasm_tls_align();
65+
tls_block = emscripten_builtin_memalign(tls_align, tls_size);
2966
}
30-
void *tls_block = emscripten_builtin_memalign(tls_align, tls_size);
3167
#ifdef DEBUG_TLS
32-
printf("tls init: thread[%p] dso[%p] -> %p\n", pthread_self(), &__dso_handle, tls_block);
68+
printf("tls init: size=%zu thread=%p dso=%p -> %p\n", tls_size, pthread_self(), &__dso_handle, tls_block);
3369
#endif
3470
__wasm_init_tls(tls_block);
3571
return tls_block;

system/lib/pthread/pthread_create.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ extern int __pthread_create_js(struct pthread *thread, const pthread_attr_t *att
2626
extern void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block);
2727
extern int _emscripten_default_pthread_stack_size();
2828
extern void __emscripten_thread_cleanup(pthread_t thread);
29-
extern void* _emscripten_tls_base();
3029
extern int8_t __dso_handle;
3130

3231
static void dummy_0()
@@ -197,15 +196,7 @@ void _emscripten_thread_free_data(pthread_t t) {
197196
emscripten_builtin_free(t);
198197
}
199198

200-
static void free_tls_data() {
201-
void* tls_block = _emscripten_tls_base();
202-
if (tls_block) {
203-
#ifdef DEBUG_TLS
204-
printf("tls free: thread[%p] dso[%p] <- %p\n", pthread_self(), &__dso_handle, tls_block);
205-
#endif
206-
emscripten_builtin_free(tls_block);
207-
}
208-
}
199+
void emscripten_tls_free(void);
209200

210201
void _emscripten_thread_exit(void* result) {
211202
struct pthread *self = __pthread_self();
@@ -221,7 +212,7 @@ void _emscripten_thread_exit(void* result) {
221212
// Call into the musl function that runs destructors of all thread-specific data.
222213
__pthread_tsd_run_dtors();
223214

224-
free_tls_data();
215+
emscripten_tls_free();
225216

226217
if (!--libc.threads_minus_1) libc.need_locks = 0;
227218

tests/test_other.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11349,7 +11349,7 @@ def test_standard_library_mapping(self):
1134911349
self.run_process([EMBUILDER, 'build', 'libc-mt-debug', 'libcompiler_rt-mt', 'libdlmalloc-mt'])
1135011350

1135111351
libs = ['-lc', '-lcompiler_rt', '-lmalloc']
11352-
err = self.run_process([EMCC, test_file('hello_world.c'), '-pthread', '-nostdlib', '-v'] + libs, stderr=PIPE).stderr
11352+
err = self.run_process([EMCC, test_file('hello_world.c'), '-pthread', '-nodefaultlibs', '-v'] + libs, stderr=PIPE).stderr
1135311353

1135411354
# Check the the linker was run with `-mt` variants because `-pthread` was passed.
1135511355
self.assertContained(' -lc-mt-debug ', err)

tools/system_libs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,7 @@ def can_use(self):
11461146
return super().can_use() and settings.STANDALONE_WASM
11471147

11481148

1149-
class crtbegin(Library):
1149+
class crtbegin(MuslInternalLibrary):
11501150
name = 'crtbegin'
11511151
cflags = ['-sUSE_PTHREADS']
11521152
src_dir = 'system/lib/pthread'

0 commit comments

Comments
 (0)