diff --git a/emcc.py b/emcc.py index 78801d2d5..a4719523f 100755 --- a/emcc.py +++ b/emcc.py @@ -1864,7 +1864,6 @@ def phase_linker_setup(options, state, newargs, settings_map): settings.JS_LIBRARIES.append((0, 'library_pthread.js')) settings.EXPORTED_FUNCTIONS += [ '___emscripten_pthread_data_constructor', - '___pthread_tsd_run_dtors', '__emscripten_call_on_thread', '__emscripten_main_thread_futex', '__emscripten_thread_init', diff --git a/src/library_pthread.js b/src/library_pthread.js index ff97026a1..356e23968 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -128,18 +128,6 @@ var LibraryPThread = { }, #endif - runExitHandlers: function() { - while (PThread.threadExitHandlers.length > 0) { - PThread.threadExitHandlers.pop()(); - } - - // Call into the musl function that runs destructors of all thread-specific data. -#if ASSERTIONS - assert(_pthread_self()) -#endif - ___pthread_tsd_run_dtors(); - }, - setExitStatus: function(status) { EXITSTATUS = status; }, @@ -949,39 +937,26 @@ var LibraryPThread = { return wasDetached ? {{{ cDefine('EINVAL') }}} : 0; }, - __pthread_exit_js__deps: ['exit'], - __pthread_exit_js: function(status) { - // Called when we are performing a pthread_exit(), either explicitly called + __pthread_exit_run_handlers__deps: ['exit'], + __pthread_exit_run_handlers: function(status) { + // Called from pthread_exit, either when called explicitly called // by programmer, or implicitly when leaving the thread main function. - if (!ENVIRONMENT_IS_PTHREAD) { - PThread.runExitHandlers(); - _exit(status); - // unreachable - } - - var tb = _pthread_self(); #if PTHREADS_DEBUG + var tb = _pthread_self(); assert(tb); out('Pthread 0x' + tb.toString(16) + ' exited.'); #endif - // Disable all cancellation so that executing the cleanup handlers won't trigger another JS - // canceled exception to be thrown. - Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.canceldisable }}} ) >> 2, 1/*PTHREAD_CANCEL_DISABLE*/); - Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.cancelasync }}} ) >> 2, 0/*PTHREAD_CANCEL_DEFERRED*/); - PThread.runExitHandlers(); - - Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.result }}} ) >> 2, status); - // When we publish this, the main thread is free to deallocate the thread object and we are done. - // Therefore set _pthread_self = 0; above to 'release' the object in this worker thread. - Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.threadStatus }}} ) >> 2, 1); // Mark the thread as no longer running. - - _emscripten_futex_wake(tb + {{{ C_STRUCTS.pthread.threadStatus }}}, {{{ cDefine('INT_MAX') }}}); // wake all threads - - // Not hosting a pthread anymore in this worker, reset the info structures to null. - __emscripten_thread_init(0, 0, 0); // Unregister the thread block inside the wasm module. + while (PThread.threadExitHandlers.length > 0) { + PThread.threadExitHandlers.pop()(); + } + }, + __pthread_exit_done: function() { + // Called at the end of pthread_exit, either when called explicitly called + // by programmer, or implicitly when leaving the thread main function. + // // Note: in theory we would like to return any offscreen canvases back to the main thread, // but if we ever fetched a rendering context for them that would not be valid, so we don't try. postMessage({ 'cmd': 'exit' }); diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index e00367439..364ce7794 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -16,9 +16,16 @@ extern int __cxa_thread_atexit(void (*)(void *), void *, void *); extern int __pthread_create_js(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -extern void __pthread_exit_js(void* status); +extern void _emscripten_thread_init(int, int, int); +extern void __pthread_exit_run_handlers(); +extern void __pthread_exit_done(); extern int8_t __dso_handle; +static void dummy_0() +{ +} +weak_alias(dummy_0, __pthread_tsd_run_dtors); + void __run_cleanup_handlers(void* _unused) { pthread_t self = __pthread_self(); while (self->cancelbuf) { @@ -48,9 +55,35 @@ int __pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*star return __pthread_create_js(thread, attr, start_routine, arg); } -void _emscripten_thread_exit(void* retval) { - assert(pthread_self()); - __pthread_exit_js(retval); +void _emscripten_thread_exit(void* result) { + struct pthread *self = __pthread_self(); + assert(self); + + self->canceldisable = PTHREAD_CANCEL_DISABLE; + self->cancelasync = PTHREAD_CANCEL_DEFERRED; + self->result = result; + + __pthread_exit_run_handlers(); + + // Call into the musl function that runs destructors of all thread-specific data. + __pthread_tsd_run_dtors(); + + if (self == emscripten_main_browser_thread_id()) { + // FIXME(sbc): When pthread_exit causes the entire application to exit + // we should be returning zero (according to the man page for pthread_exit). + exit((intptr_t)result); + return; + } + + // Mark the thread as no longer running. + // When we publish this, the main thread is free to deallocate the thread object and we are done. + self->threadStatus = 1; + + emscripten_futex_wake(&self->threadStatus, INT_MAX); // wake all threads + + // Not hosting a pthread anymore in this worker, reset the info structures to null. + _emscripten_thread_init(0, 0, 0); // Unregister the thread block inside the wasm module. + __pthread_exit_done(); } // Mark as `no_sanitize("address"` since emscripten_pthread_exit destroys diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports index 2b1bb838e..2dd235d73 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports @@ -14,8 +14,7 @@ M N O P -t -u +Q v w x diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs index 255a14931..30d18c9ea 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs @@ -7,7 +7,6 @@ $__pthread_mutex_trylock $__pthread_mutex_unlock $__pthread_self_internal $__pthread_setcancelstate -$__pthread_tsd_run_dtors $__wasm_call_ctors $__wasm_init_memory $_do_call diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports index 184585564..014f2e229 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports @@ -17,3 +17,5 @@ a.p a.q a.r a.s +a.t +a.u diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent index 694fe82a2..ad11ff431 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent @@ -17,3 +17,5 @@ p q r s +t +u