Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------------------
Expand Down
3 changes: 3 additions & 0 deletions src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +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['_emscripten_tls_init']();
#endif
#if STACK_OVERFLOW_CHECK
{{{ makeAsmGlobalAccessInPthread('writeStackCookie') }}}();
#endif
Expand Down
2 changes: 1 addition & 1 deletion system/lib/libc/musl/src/misc/emscripten_pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 14 additions & 0 deletions system/lib/pthread/library_pthread_wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(100)))
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);
}
}
32 changes: 32 additions & 0 deletions tests/pthread/test_pthread_tls.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <thread>
#include <cstdio>

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
}
16 changes: 16 additions & 0 deletions tests/pthread/test_pthread_tls_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <thread>
#include <cstdio>

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 + tls2);
#endif
}
12 changes: 12 additions & 0 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3892,6 +3892,18 @@ def test_pthread_utf8_funcs(self):
def test_pthread_wake_all(self):
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)

# 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=['-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=['-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):
Expand Down