Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces thread-safety assertions for the File System (FS) on pthreads, proxies embedded file loading to the main thread, and adds a new test for loading embedded files via dlopen on a pthread. The review feedback highlights two main issues: first, in the new C test, returning from the thread main function during an asynchronous dlopen can prematurely terminate the thread runtime, so emscripten_exit_with_live_runtime() should be used instead; second, the Python test violates the newly added documentation guidelines by mutating self.cflags directly rather than passing compiler flags inline.
| #ifdef USE_ASYNC_DLOPEN | ||
| emscripten_dlopen("libside.so", RTLD_NOW | RTLD_GLOBAL, NULL, on_dl_success, on_dl_fail); | ||
| #else | ||
| void* handle = dlopen("libside.so", RTLD_NOW | RTLD_GLOBAL); | ||
| assert(handle); | ||
| func_t read_embedded_file = (func_t)dlsym(handle, "read_embedded_file"); | ||
| assert(read_embedded_file); | ||
| read_embedded_file(); | ||
| check_embedded_file("pthread"); | ||
| dlclose(handle); | ||
| thread_done = true; | ||
| #endif | ||
| return NULL; |
There was a problem hiding this comment.
When using asynchronous emscripten_dlopen on a pthread, returning NULL from thread_main immediately exits the thread and cleans up its resources. This can prevent the asynchronous on_dl_success callback from executing, or cause it to run on a defunct thread context, leading to undefined behavior or test flakiness. To keep the thread's runtime alive so it can process the async callback, use emscripten_exit_with_live_runtime() instead of returning.
#ifdef USE_ASYNC_DLOPEN
emscripten_dlopen("libside.so", RTLD_NOW | RTLD_GLOBAL, NULL, on_dl_success, on_dl_fail);
emscripten_exit_with_live_runtime();
#else
void* handle = dlopen("libside.so", RTLD_NOW | RTLD_GLOBAL);
assert(handle);
func_t read_embedded_file = (func_t)dlsym(handle, "read_embedded_file");
assert(read_embedded_file);
read_embedded_file();
check_embedded_file("pthread");
dlclose(handle);
thread_done = true;
return NULL;
#endif| self.cflags += ['-Wno-experimental', '-pthread'] | ||
| self.build_dlfcn_lib(test_file('core/pthread/test_pthread_dlopen_embed_side.c'), | ||
| cflags=['--embed-file', 'embedded.txt']) | ||
|
|
||
| self.prep_dlfcn_main() | ||
| self.do_runf('core/pthread/test_pthread_dlopen_embed.c', 'done\n', | ||
| cflags=args + ['-sEXIT_RUNTIME']) |
There was a problem hiding this comment.
This test mutates self.cflags directly, which violates the newly added guideline in docs/process.md stating that compiler/linker flags should be passed via inline cflags= arguments to test methods rather than mutating self.cflags. We can pass the flags directly to build_dlfcn_lib and do_runf instead.
self.build_dlfcn_lib(test_file('core/pthread/test_pthread_dlopen_embed_side.c'),
cflags=['--embed-file', 'embedded.txt', '-Wno-experimental', '-pthread'])
self.prep_dlfcn_main()
self.do_runf('core/pthread/test_pthread_dlopen_embed.c', 'done\n',
cflags=args + ['-sEXIT_RUNTIME', '-Wno-experimental', '-pthread'])When a side module built with `--embed-file` is `dlopen`ed from a pthread, its static constructors run on that worker thread (`firstLoad` is true there). Without `__proxy: 'sync'`, `_emscripten_fs_load_embedded_files` populated the worker's local `FS` (or un-flushed WasmFS preloaded arrays) instead of the main thread's filesystem. Also, add some assertions to make this kind of thing easier to detect in the future. Fixes: emscripten-core#28256
59ac0af to
ab986a1
Compare
When a side module built with
--embed-fileisdlopened from a pthread, its static constructors run on that worker thread (firstLoadis true there). Without__proxy: 'sync',_emscripten_fs_load_embedded_filespopulated the worker's localFS(or un-flushed WasmFS preloaded arrays) instead of the main thread's filesystem.Also, add some assertions to make this kind of thing easier to detect in the future.
Fixes: #28256