Skip to content

Commit

Permalink
pthread+dylink: Ensure code is in sync on thread start
Browse files Browse the repository at this point in the history
We still don't have a great way to keep threads in sync but this
at least means they will be correct at the moment the start.

Part of #3494.

Fixes: #16021
  • Loading branch information
sbc100 committed Feb 10, 2022
1 parent 6262af1 commit 84ab9ab
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 6 deletions.
4 changes: 4 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2044,6 +2044,10 @@ def default_setting(name, new_default):
'emscripten_sync_run_in_main_thread_2',
'emscripten_sync_run_in_main_thread_4',
]

if settings.MAIN_MODULE:
settings.REQUIRED_EXPORTS += ['_emscripten_thread_sync_code', '__dl_seterr']

settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += [
'$exitOnMainThread',
]
Expand Down
26 changes: 20 additions & 6 deletions src/library_dylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ var LibraryDylink = {
err("unhandled export type for `" + symName + "`: " + (typeof value));
}
#if DYLINK_DEBUG
err("updateGOT: after: " + symName + ' : ' + GOT[symName].value);
err("updateGOT: after: " + symName + ' : ' + GOT[symName].value + ' (' + value + ')');
#endif
}
#if DYLINK_DEBUG
else if (GOT[symName].value != value) {
err("updateGOT: EXISTING SYMBOL: " + symName + ' : ' + GOT[symName].value + " " + value);
err("updateGOT: EXISTING SYMBOL: " + symName + ' : ' + GOT[symName].value + ' (' + value + ')');
}
#endif
}
Expand Down Expand Up @@ -427,6 +427,13 @@ var LibraryDylink = {
}
},

#if DYLINK_DEBUG
$dumpTable: function() {
for (var i = 0; i < wasmTable.length; i++)
err('table: ' + i + ' : ' + wasmTable.get(i));
},
#endif

// Loads a side module from binary data or compiled Module. Returns the module's exports or a
// promise that resolves to its exports if the loadAsync flag is set.
$loadWebAssemblyModule__deps: [
Expand Down Expand Up @@ -649,6 +656,7 @@ var LibraryDylink = {
$loadDynamicLibrary: function(lib, flags, handle) {
#if DYLINK_DEBUG
err('loadDynamicLibrary: ' + lib + ' handle:' + handle);
err('existing: ' + Object.keys(LDSO.loadedLibsByName));
#endif
if (lib == '__main__' && !LDSO.loadedLibsByName[lib]) {
LDSO.loadedLibsByName[lib] = {
Expand Down Expand Up @@ -798,7 +806,7 @@ var LibraryDylink = {
},

// void* dlopen(const char* filename, int flags);
$dlopenInternal__deps: ['$FS', '$ENV', '$dlSetError'],
$dlopenInternal__deps: ['$FS', '$ENV', '$dlSetError', '$PATH'],
$dlopenInternal: function(handle, jsflags) {
// void *dlopen(const char *file, int mode);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
Expand All @@ -807,6 +815,7 @@ var LibraryDylink = {
#if DYLINK_DEBUG
err('dlopenInternal: ' + filename);
#endif
filename = PATH.normalize(filename);
var searchpaths = [];

var isValidFile = (filename) => {
Expand Down Expand Up @@ -933,14 +942,19 @@ var LibraryDylink = {
}

if (typeof result === 'function') {
#if DYLINK_DEBUG
err('dlsym: ' + symbol + ' getting table slot for: ' + result);
#endif
// Insert the function into the wasm table. If its a direct wasm function
// the second argument will not be needed. If its a JS function we rely
// on the `sig` attribute being set based on the `<func>__sig` specified
// in library JS file.
return addFunction(result, result.sig);
} else {
return result;
result = addFunction(result, result.sig);
}
#if DYLINK_DEBUG
err('dlsym: ' + symbol + ' -> ' + result);
#endif
return result;
},
#endif // MAIN_MODULE != 0
};
Expand Down
6 changes: 6 additions & 0 deletions src/library_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,12 @@ var LibraryPThread = {
$invokeEntryPoint: function(ptr, arg) {
#if PTHREADS_DEBUG
err('invokeEntryPoint: ' + ptrToString(ptr));
#endif
#if MAIN_MODULE
// Before we call the thread entry point, make sure any shared libraries
// have been loaded on this there. Otherwise our table migth be not be
// in sync and might not contain the function pointer `ptr` at all.
__emscripten_thread_sync_code();
#endif
return {{{ makeDynCall('ii', 'ptr') }}}(arg);
},
Expand Down
30 changes: 30 additions & 0 deletions tests/core/pthread/test_pthread_dylink_entry_point.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <stdio.h>
#include <dlfcn.h>
#include <pthread.h>

typedef void* (*thread_main_t)(void*);

int main() {
puts("hello from main");

void *lib_handle = dlopen("./liblib.so", RTLD_NOW);
if (!lib_handle) {
puts("cannot load side module");
puts(dlerror());
return 1;
}

thread_main_t tmain = (thread_main_t)dlsym(lib_handle, "side_module_thread_main");
if (!tmain) {
puts("cannot find side function");
return 1;
}

printf("starting thread with %p\n", tmain);
pthread_t t;
pthread_create(&t, NULL, tmain, (void*)"hello");
pthread_join(t, NULL);

printf("done\n");
return 0;
}
1 change: 1 addition & 0 deletions tests/core/pthread/test_pthread_dylink_entry_point.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
call thread fn in side: hello
8 changes: 8 additions & 0 deletions tests/core/pthread/test_pthread_dylink_entry_point_side.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <stdio.h>
#include <emscripten.h>
#include <pthread.h>

EMSCRIPTEN_KEEPALIVE void* side_module_thread_main(void* arg) {
printf("call thread fn in side: %s\n", (char*)arg);
return NULL;
}
14 changes: 14 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8681,6 +8681,20 @@ def test_pthread_dylink(self):
self.dylink_testf(main, so_name=very_long_name,
need_reverse=False)

@parameterized({
'': (['-sNO_AUTOLOAD_DYLIBS'],),
'autoload': ([],)
})
@needs_dylink
@node_pthreads
def test_pthread_dylink_entry_point(self, args):
self.emcc_args.append('-Wno-experimental')
self.set_setting('EXIT_RUNTIME')
self.set_setting('USE_PTHREADS')
self.set_setting('PTHREAD_POOL_SIZE', 1)
main = test_file('core/pthread/test_pthread_dylink_entry_point.c')
self.dylink_testf(main, need_reverse=False, emcc_args=args)

@needs_dylink
@node_pthreads
def test_pthread_dlopen(self):
Expand Down

0 comments on commit 84ab9ab

Please sign in to comment.