From 3c751efbee9aa1ebed99239d0385b1cc4101c279 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Fri, 12 Jul 2019 16:29:08 -0700 Subject: [PATCH 01/10] Implement initialization for local-exec TLS Depends on https://reviews.llvm.org/D64537 --- src/worker.js | 1 + system/lib/pthread/library_pthread.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/worker.js b/src/worker.js index 643a225fa6ab2..f444c96cbc9ed 100644 --- a/src/worker.js +++ b/src/worker.js @@ -207,6 +207,7 @@ this.onmessage = function(e) { // Also call inside JS module to set up the stack frame for this pthread in JS module scope Module['establishStackSpaceInJsModule'](e.data.stackBase, e.data.stackBase + e.data.stackSize); #endif + Module['asm']['emscripten_tls_init'](); #if STACK_OVERFLOW_CHECK {{{ makeAsmGlobalAccessInPthread('writeStackCookie') }}}(); #endif diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index e36d956dc3dd4..ea3a49fa8ba20 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -956,3 +956,16 @@ int EMSCRIPTEN_KEEPALIVE proxy_main(int argc, char** argv) { } weak_alias(__pthread_testcancel, pthread_testcancel); + +extern void __wasm_init_tls(void *memory); +void *emscripten_builtin_malloc(size_t size); +void emscripten_builtin_free(void *memory); + +void EMSCRIPTEN_KEEPALIVE emscripten_tls_init(void) { + size_t tls_size = __builtin_wasm_tls_size(); + if (tls_size) { + void *tls_block = emscripten_builtin_malloc(tls_size); + __wasm_init_tls(tls_block); + pthread_cleanup_push(emscripten_builtin_free, tls_block); + } +} From a9370cc2364bd5d1092f04953adacbd498e4515d Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Fri, 12 Jul 2019 17:04:01 -0700 Subject: [PATCH 02/10] Add unit tests for local-exec TLS --- tests/pthread/test_pthread_tls.cpp | 18 ++++++++++++++++++ tests/test_browser.py | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/pthread/test_pthread_tls.cpp diff --git a/tests/pthread/test_pthread_tls.cpp b/tests/pthread/test_pthread_tls.cpp new file mode 100644 index 0000000000000..6ca804b3a6ea4 --- /dev/null +++ b/tests/pthread/test_pthread_tls.cpp @@ -0,0 +1,18 @@ +#include +#include + +thread_local int tls; + +void thread(void) { + ++tls; + assert(tls == 1); +} + +int main(void) { + std::thread t(thread); + t.join(); + assert(tls == 0); +#ifdef REPORT_RESULT + REPORT_RESULT(1337); +#endif +} diff --git a/tests/test_browser.py b/tests/test_browser.py index da2512a20b31f..12dda81db0d65 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3888,6 +3888,12 @@ def test_pthread_clock_drift(self): def test_pthread_utf8_funcs(self): self.btest(path_from_root('tests', 'pthread', 'test_pthread_utf8_funcs.cpp'), expected='0', args=['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=1']) + # Test that real `thread_local` works. + @no_fastcomp('thread_local is only supported on WASM backend') + @requires_threads + def test_pthread_tls(self): + self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls.cpp'), expected='1337', args=['-ftls-model=local-exec', '-s', 'PROXY_TO_PTHREAD', '-s', 'USE_PTHREADS', '-std=c++11']) + # Tests MAIN_THREAD_EM_ASM_INT() function call signatures. @no_wasm_backend('MAIN_THREAD_EM_ASM() not yet implemented in Wasm backend') def test_main_thread_em_asm_signatures(self): From 533cd0cf1272b78c7d384d33cf2ff21a0732f551 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Fri, 12 Jul 2019 17:15:04 -0700 Subject: [PATCH 03/10] Ensure TLS works on the true main thread as well --- system/lib/pthread/library_pthread.c | 1 + tests/pthread/test_pthread_tls_main.cpp | 10 ++++++++++ tests/test_browser.py | 6 ++++++ 3 files changed, 17 insertions(+) create mode 100644 tests/pthread/test_pthread_tls_main.cpp diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index ea3a49fa8ba20..0a418cd1b1e3b 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -961,6 +961,7 @@ extern void __wasm_init_tls(void *memory); void *emscripten_builtin_malloc(size_t size); void emscripten_builtin_free(void *memory); +__attribute__((constructor)) void EMSCRIPTEN_KEEPALIVE emscripten_tls_init(void) { size_t tls_size = __builtin_wasm_tls_size(); if (tls_size) { diff --git a/tests/pthread/test_pthread_tls_main.cpp b/tests/pthread/test_pthread_tls_main.cpp new file mode 100644 index 0000000000000..efb02531085df --- /dev/null +++ b/tests/pthread/test_pthread_tls_main.cpp @@ -0,0 +1,10 @@ +#include +#include + +thread_local int tls = 1337; + +int main(void) { +#ifdef REPORT_RESULT + REPORT_RESULT(tls); +#endif +} diff --git a/tests/test_browser.py b/tests/test_browser.py index 12dda81db0d65..8630a783f1c90 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3894,6 +3894,12 @@ def test_pthread_utf8_funcs(self): def test_pthread_tls(self): self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls.cpp'), expected='1337', args=['-ftls-model=local-exec', '-s', 'PROXY_TO_PTHREAD', '-s', 'USE_PTHREADS', '-std=c++11']) + # Test that real `thread_local` works in main thread without PROXY_TO_PTHREAD. + @no_fastcomp('thread_local is only supported on WASM backend') + @requires_threads + def test_pthread_tls_main(self): + self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls_main.cpp'), expected='1337', args=['-ftls-model=local-exec', '-s', 'USE_PTHREADS', '-std=c++11']) + # Tests MAIN_THREAD_EM_ASM_INT() function call signatures. @no_wasm_backend('MAIN_THREAD_EM_ASM() not yet implemented in Wasm backend') def test_main_thread_em_asm_signatures(self): From 80694ad709ff2650e2c66982f3bdb9fe3029b1de Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Fri, 12 Jul 2019 17:43:37 -0700 Subject: [PATCH 04/10] Test more POD types with thread local --- tests/pthread/test_pthread_tls.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/pthread/test_pthread_tls.cpp b/tests/pthread/test_pthread_tls.cpp index 6ca804b3a6ea4..1acf666227638 100644 --- a/tests/pthread/test_pthread_tls.cpp +++ b/tests/pthread/test_pthread_tls.cpp @@ -2,16 +2,30 @@ #include thread_local int tls; +thread_local struct { + int a; + double b; +} data = {1, 2}; +thread_local int array[10]; void thread(void) { ++tls; + data.a = 3; + data.b = 4; assert(tls == 1); + assert(data.a == 3); + assert(data.b == 4); + assert(array[9] == 0); } int main(void) { + array[9] = 1337; std::thread t(thread); t.join(); assert(tls == 0); + assert(data.a == 1); + assert(data.b == 2); + assert(array[9] == 1337); #ifdef REPORT_RESULT REPORT_RESULT(1337); #endif From f6f91c2f52a552e421cdba5b14d7b27b61acc8d5 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Mon, 15 Jul 2019 10:23:23 -0700 Subject: [PATCH 05/10] Move TLS to library_pthread_wasm.c --- system/lib/pthread/library_pthread.c | 14 -------------- system/lib/pthread/library_pthread_wasm.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 0a418cd1b1e3b..e36d956dc3dd4 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -956,17 +956,3 @@ int EMSCRIPTEN_KEEPALIVE proxy_main(int argc, char** argv) { } weak_alias(__pthread_testcancel, pthread_testcancel); - -extern void __wasm_init_tls(void *memory); -void *emscripten_builtin_malloc(size_t size); -void emscripten_builtin_free(void *memory); - -__attribute__((constructor)) -void EMSCRIPTEN_KEEPALIVE emscripten_tls_init(void) { - size_t tls_size = __builtin_wasm_tls_size(); - if (tls_size) { - void *tls_block = emscripten_builtin_malloc(tls_size); - __wasm_init_tls(tls_block); - pthread_cleanup_push(emscripten_builtin_free, tls_block); - } -} diff --git a/system/lib/pthread/library_pthread_wasm.c b/system/lib/pthread/library_pthread_wasm.c index 79ada9ec8de1b..c5da9e56575cd 100644 --- a/system/lib/pthread/library_pthread_wasm.c +++ b/system/lib/pthread/library_pthread_wasm.c @@ -168,3 +168,17 @@ uint32_t emscripten_atomic_xor_u32(void /*uint32_t*/* addr, uint32_t val) { uint64_t emscripten_atomic_xor_u64(void /*uint64_t*/* addr, uint64_t val) { return __c11_atomic_fetch_xor((_Atomic uint64_t*)addr, val, __ATOMIC_SEQ_CST); } + +extern void __wasm_init_tls(void *memory); +void *emscripten_builtin_malloc(size_t size); +void emscripten_builtin_free(void *memory); + +__attribute__((constructor)) +void EMSCRIPTEN_KEEPALIVE emscripten_tls_init(void) { + size_t tls_size = __builtin_wasm_tls_size(); + if (tls_size) { + void *tls_block = emscripten_builtin_malloc(tls_size); + __wasm_init_tls(tls_block); + pthread_cleanup_push(emscripten_builtin_free, tls_block); + } +} From e86b4f566c3af7d7e9a7909d58b0e4994bb8b157 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Mon, 15 Jul 2019 16:47:40 -0700 Subject: [PATCH 06/10] Support thread-locals in __attribute((constructor)) --- system/lib/libc/musl/src/misc/emscripten_pthread.c | 2 +- system/lib/pthread/library_pthread_wasm.c | 2 +- tests/pthread/test_pthread_tls_main.cpp | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/system/lib/libc/musl/src/misc/emscripten_pthread.c b/system/lib/libc/musl/src/misc/emscripten_pthread.c index ed8f8c0b9b3be..5bff59452e700 100644 --- a/system/lib/libc/musl/src/misc/emscripten_pthread.c +++ b/system/lib/libc/musl/src/misc/emscripten_pthread.c @@ -25,7 +25,7 @@ EM_JS(void, initPthreadsJS, (void), { }) EMSCRIPTEN_KEEPALIVE -__attribute__((constructor(100))) // This must run before any userland ctors +__attribute__((constructor(99))) // This must run before any userland ctors void __emscripten_pthread_data_constructor(void) { initPthreadsJS(); pthread_self()->locale = &libc.global_locale; diff --git a/system/lib/pthread/library_pthread_wasm.c b/system/lib/pthread/library_pthread_wasm.c index c5da9e56575cd..ecf89d59ba68e 100644 --- a/system/lib/pthread/library_pthread_wasm.c +++ b/system/lib/pthread/library_pthread_wasm.c @@ -173,7 +173,7 @@ extern void __wasm_init_tls(void *memory); void *emscripten_builtin_malloc(size_t size); void emscripten_builtin_free(void *memory); -__attribute__((constructor)) +__attribute__((constructor(100))) void EMSCRIPTEN_KEEPALIVE emscripten_tls_init(void) { size_t tls_size = __builtin_wasm_tls_size(); if (tls_size) { diff --git a/tests/pthread/test_pthread_tls_main.cpp b/tests/pthread/test_pthread_tls_main.cpp index efb02531085df..a78e42f7ecf39 100644 --- a/tests/pthread/test_pthread_tls_main.cpp +++ b/tests/pthread/test_pthread_tls_main.cpp @@ -1,10 +1,16 @@ #include #include -thread_local int tls = 1337; +thread_local int tls = 1330; +thread_local int tls2; + +__attribute__((constructor)) +void init_tls2(void) { + tls2 = 7; +} int main(void) { #ifdef REPORT_RESULT - REPORT_RESULT(tls); + REPORT_RESULT(tls + tls2); #endif } From 79982209e7e8240ecff9409026df367500bbc5d7 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Tue, 16 Jul 2019 12:46:47 -0700 Subject: [PATCH 07/10] Remove -ftls-model=local-exec --- tests/test_browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_browser.py b/tests/test_browser.py index ef971abd98146..7b996cd19cc50 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3898,13 +3898,13 @@ def test_pthread_wake_all(self): @no_fastcomp('thread_local is only supported on WASM backend') @requires_threads def test_pthread_tls(self): - self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls.cpp'), expected='1337', args=['-ftls-model=local-exec', '-s', 'PROXY_TO_PTHREAD', '-s', 'USE_PTHREADS', '-std=c++11']) + self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls.cpp'), expected='1337', args=['-s', 'PROXY_TO_PTHREAD', '-s', 'USE_PTHREADS', '-std=c++11']) # Test that real `thread_local` works in main thread without PROXY_TO_PTHREAD. @no_fastcomp('thread_local is only supported on WASM backend') @requires_threads def test_pthread_tls_main(self): - self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls_main.cpp'), expected='1337', args=['-ftls-model=local-exec', '-s', 'USE_PTHREADS', '-std=c++11']) + self.btest(path_from_root('tests', 'pthread', 'test_pthread_tls_main.cpp'), expected='1337', args=['-s', 'USE_PTHREADS', '-std=c++11']) # Tests MAIN_THREAD_EM_ASM_INT() function call signatures. @no_wasm_backend('MAIN_THREAD_EM_ASM() not yet implemented in Wasm backend') From 6f26c231ec5b3fc451de8680878e614095c792d0 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Wed, 17 Jul 2019 13:55:02 -0700 Subject: [PATCH 08/10] Don't break fastcomp calling wasm-backend-specific stuff --- src/worker.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/worker.js b/src/worker.js index f444c96cbc9ed..83483c0fdd137 100644 --- a/src/worker.js +++ b/src/worker.js @@ -207,7 +207,9 @@ this.onmessage = function(e) { // Also call inside JS module to set up the stack frame for this pthread in JS module scope Module['establishStackSpaceInJsModule'](e.data.stackBase, e.data.stackBase + e.data.stackSize); #endif +#if WASM_BACKEND Module['asm']['emscripten_tls_init'](); +#endif #if STACK_OVERFLOW_CHECK {{{ makeAsmGlobalAccessInPthread('writeStackCookie') }}}(); #endif From b1c2e77586f74161dc41a87cb6e95b990bc7f717 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Wed, 17 Jul 2019 15:27:40 -0700 Subject: [PATCH 09/10] Fix pthread tests hanging --- src/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worker.js b/src/worker.js index 83483c0fdd137..3a79f5ab89a1f 100644 --- a/src/worker.js +++ b/src/worker.js @@ -208,7 +208,7 @@ this.onmessage = function(e) { Module['establishStackSpaceInJsModule'](e.data.stackBase, e.data.stackBase + e.data.stackSize); #endif #if WASM_BACKEND - Module['asm']['emscripten_tls_init'](); + Module['_emscripten_tls_init'](); #endif #if STACK_OVERFLOW_CHECK {{{ makeAsmGlobalAccessInPthread('writeStackCookie') }}}(); From 7aa69c532321345e22c023eafd8d3d8a4d9c8b42 Mon Sep 17 00:00:00 2001 From: Guanzhong Chen Date: Wed, 17 Jul 2019 15:33:10 -0700 Subject: [PATCH 10/10] Add to change log --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 42a72c453b7d2..ff6e418be0f92 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -21,6 +21,8 @@ Current Trunk - LLVM backend pthread builds no longer use external memory initialization files, replacing them with passive data segments. + - LLVM backend now supports thread local storage via the C extension `__thread` + and C11/C++11 keyword `thread_local`. (#8976) v1.38.39: 07/16/2019 --------------------