Skip to content

Commit 3d342b8

Browse files
committed
Don't use wasm global data sections when compiling with multithreading enabled so that pthread_create() will not reset the global data members. Instead use a separate .mem file or base64-embedded data in JS file for memory initialization. See WebAssembly/threads#62
1 parent df02ead commit 3d342b8

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

emcc.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -1675,7 +1675,7 @@ def repl(m):
16751675
if DEBUG:
16761676
# Copy into temp dir as well, so can be run there too
16771677
shared.safe_copy(memfile, os.path.join(shared.get_emscripten_temp_dir(), os.path.basename(memfile)))
1678-
if not shared.Settings.BINARYEN or 'asmjs' in shared.Settings.BINARYEN_METHOD or 'interpret-asm2wasm' in shared.Settings.BINARYEN_METHOD:
1678+
if not shared.Settings.BINARYEN or 'asmjs' in shared.Settings.BINARYEN_METHOD or 'interpret-asm2wasm' in shared.Settings.BINARYEN_METHOD or shared.Settings.USE_PTHREADS:
16791679
return 'memoryInitializer = "%s";' % shared.JS.get_subresource_location(memfile, embed_memfile(options))
16801680
else:
16811681
return 'memoryInitializer = null;'
@@ -2267,9 +2267,12 @@ def do_binaryen(final, target, asm_target, options, memfile, wasm_binary_target,
22672267
if options.opt_level > 0:
22682268
cmd.append(shared.Building.opt_level_to_str(options.opt_level, options.shrink_level))
22692269
# import mem init file if it exists, and if we will not be using asm.js as a binaryen method (as it needs the mem init file, of course)
2270+
# Note that importing (embedding) memory init file into the .wasm module as a data section is not compatible with multithreading in WebAssembly,
2271+
# because each thread would reinitialize the global data section at thread creation time, so only embed a data section to the generated
2272+
# .wasm file if not using multithreading
22702273
mem_file_exists = options.memory_init_file and os.path.exists(memfile)
22712274
ok_binaryen_method = 'asmjs' not in shared.Settings.BINARYEN_METHOD and 'interpret-asm2wasm' not in shared.Settings.BINARYEN_METHOD
2272-
import_mem_init = mem_file_exists and ok_binaryen_method
2275+
import_mem_init = mem_file_exists and ok_binaryen_method and not shared.Settings.USE_PTHREADS
22732276
if import_mem_init:
22742277
cmd += ['--mem-init=' + memfile]
22752278
if not shared.Settings.RELOCATABLE:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <assert.h>
2+
#include <pthread.h>
3+
#include <emscripten.h>
4+
5+
int globalData = 1;
6+
7+
void *thread_main(void *arg)
8+
{
9+
EM_ASM(Module.print('hello from pthread 1: ' + $0), globalData);
10+
assert(globalData == 10);
11+
12+
globalData = 20;
13+
EM_ASM(Module.print('hello from pthread 2: ' + $0), globalData);
14+
assert(globalData == 20);
15+
return 0;
16+
}
17+
18+
int main()
19+
{
20+
EM_ASM(Module.print('hello from main 1: ' + $0), globalData);
21+
assert(globalData == 1);
22+
23+
globalData = 10;
24+
EM_ASM(Module.print('hello from main 2: ' + $0), globalData);
25+
assert(globalData == 10);
26+
27+
pthread_t thread;
28+
pthread_create(&thread, NULL, thread_main, NULL);
29+
pthread_join(thread, 0);
30+
31+
EM_ASM(Module.print('hello from main 3: ' + $0), globalData);
32+
assert(globalData == 20);
33+
#ifdef REPORT_RESULT
34+
REPORT_RESULT(globalData);
35+
#endif
36+
}

tests/test_browser.py

+6
Original file line numberDiff line numberDiff line change
@@ -3362,6 +3362,12 @@ def test_pthread_call_async_on_main_thread(self):
33623362
self.btest_wasm(path_from_root('tests', 'pthread', 'call_async_on_main_thread.c'), expected='7', args=['-O3', '-s', 'USE_PTHREADS=1', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_async_on_main_thread.js')])
33633363
self.btest_wasm(path_from_root('tests', 'pthread', 'call_async_on_main_thread.c'), expected='7', args=['-Oz', '-DPROXY_TO_PTHREAD=0', '--js-library', path_from_root('tests', 'pthread', 'call_async_on_main_thread.js')])
33643364

3365+
# Tests that spawning a new thread does not cause a reinitialization of the global data section of the application memory area.
3366+
def test_pthread_global_data_initialization(self):
3367+
for mem_init_mode in [[], ['--memory-init-file', '0'], ['--memory-init-file', '1'], ['--memory-init-file', '2']]:
3368+
for args in [[], ['-O3']]:
3369+
self.btest_wasm(path_from_root('tests', 'pthread', 'test_pthread_global_data_initialization.c'), expected='20', args=args+mem_init_mode+['-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1'])
3370+
33653371
# test atomicrmw i64
33663372
def test_atomicrmw_i64(self):
33673373
Popen([PYTHON, EMCC, path_from_root('tests', 'atomicrmw_i64.ll'), '-s', 'USE_PTHREADS=1', '-s', 'IN_TEST_HARNESS=1', '-o', 'test.html']).communicate()

0 commit comments

Comments
 (0)