Skip to content

Commit 9602b80

Browse files
authored
Implement initialization for local-exec TLS (#8976)
1 parent 6eb264b commit 9602b80

File tree

7 files changed

+80
-1
lines changed

7 files changed

+80
-1
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Current Trunk
2121

2222
- LLVM backend pthread builds no longer use external memory initialization
2323
files, replacing them with passive data segments.
24+
- LLVM backend now supports thread local storage via the C extension `__thread`
25+
and C11/C++11 keyword `thread_local`. (#8976)
2426

2527
v1.38.39: 07/16/2019
2628
--------------------

src/worker.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ this.onmessage = function(e) {
207207
// Also call inside JS module to set up the stack frame for this pthread in JS module scope
208208
Module['establishStackSpaceInJsModule'](e.data.stackBase, e.data.stackBase + e.data.stackSize);
209209
#endif
210+
#if WASM_BACKEND
211+
Module['_emscripten_tls_init']();
212+
#endif
210213
#if STACK_OVERFLOW_CHECK
211214
{{{ makeAsmGlobalAccessInPthread('writeStackCookie') }}}();
212215
#endif

system/lib/libc/musl/src/misc/emscripten_pthread.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ EM_JS(void, initPthreadsJS, (void), {
2525
})
2626

2727
EMSCRIPTEN_KEEPALIVE
28-
__attribute__((constructor(100))) // This must run before any userland ctors
28+
__attribute__((constructor(99))) // This must run before any userland ctors
2929
void __emscripten_pthread_data_constructor(void) {
3030
initPthreadsJS();
3131
pthread_self()->locale = &libc.global_locale;

system/lib/pthread/library_pthread_wasm.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,17 @@ uint32_t emscripten_atomic_xor_u32(void /*uint32_t*/* addr, uint32_t val) {
168168
uint64_t emscripten_atomic_xor_u64(void /*uint64_t*/* addr, uint64_t val) {
169169
return __c11_atomic_fetch_xor((_Atomic uint64_t*)addr, val, __ATOMIC_SEQ_CST);
170170
}
171+
172+
extern void __wasm_init_tls(void *memory);
173+
void *emscripten_builtin_malloc(size_t size);
174+
void emscripten_builtin_free(void *memory);
175+
176+
__attribute__((constructor(100)))
177+
void EMSCRIPTEN_KEEPALIVE emscripten_tls_init(void) {
178+
size_t tls_size = __builtin_wasm_tls_size();
179+
if (tls_size) {
180+
void *tls_block = emscripten_builtin_malloc(tls_size);
181+
__wasm_init_tls(tls_block);
182+
pthread_cleanup_push(emscripten_builtin_free, tls_block);
183+
}
184+
}

tests/pthread/test_pthread_tls.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <thread>
2+
#include <cstdio>
3+
4+
thread_local int tls;
5+
thread_local struct {
6+
int a;
7+
double b;
8+
} data = {1, 2};
9+
thread_local int array[10];
10+
11+
void thread(void) {
12+
++tls;
13+
data.a = 3;
14+
data.b = 4;
15+
assert(tls == 1);
16+
assert(data.a == 3);
17+
assert(data.b == 4);
18+
assert(array[9] == 0);
19+
}
20+
21+
int main(void) {
22+
array[9] = 1337;
23+
std::thread t(thread);
24+
t.join();
25+
assert(tls == 0);
26+
assert(data.a == 1);
27+
assert(data.b == 2);
28+
assert(array[9] == 1337);
29+
#ifdef REPORT_RESULT
30+
REPORT_RESULT(1337);
31+
#endif
32+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <thread>
2+
#include <cstdio>
3+
4+
thread_local int tls = 1330;
5+
thread_local int tls2;
6+
7+
__attribute__((constructor))
8+
void init_tls2(void) {
9+
tls2 = 7;
10+
}
11+
12+
int main(void) {
13+
#ifdef REPORT_RESULT
14+
REPORT_RESULT(tls + tls2);
15+
#endif
16+
}

tests/test_browser.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3892,6 +3892,18 @@ def test_pthread_utf8_funcs(self):
38923892
def test_pthread_wake_all(self):
38933893
self.btest(path_from_root('tests', 'pthread', 'test_futex_wake_all.cpp'), expected='0', args=['-O3', '-s', 'USE_PTHREADS=1', '-s', 'TOTAL_MEMORY=64MB', '-s', 'NO_EXIT_RUNTIME=1'], also_asmjs=True)
38943894

3895+
# Test that real `thread_local` works.
3896+
@no_fastcomp('thread_local is only supported on WASM backend')
3897+
@requires_threads
3898+
def test_pthread_tls(self):
3899+
self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls.cpp'), expected='1337', args=['-s', 'PROXY_TO_PTHREAD', '-s', 'USE_PTHREADS', '-std=c++11'])
3900+
3901+
# Test that real `thread_local` works in main thread without PROXY_TO_PTHREAD.
3902+
@no_fastcomp('thread_local is only supported on WASM backend')
3903+
@requires_threads
3904+
def test_pthread_tls_main(self):
3905+
self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls_main.cpp'), expected='1337', args=['-s', 'USE_PTHREADS', '-std=c++11'])
3906+
38953907
# Tests MAIN_THREAD_EM_ASM_INT() function call signatures.
38963908
@no_wasm_backend('MAIN_THREAD_EM_ASM() not yet implemented in Wasm backend')
38973909
def test_main_thread_em_asm_signatures(self):

0 commit comments

Comments
 (0)