From dee8e724965ebea248a6b74113124e915791b6dd Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 8 Nov 2021 17:54:41 -0800 Subject: [PATCH] Move pthread_tryjoin_np to native code This matches more closely the musl version. --- src/library_pthread.js | 47 ++------------------- system/lib/pthread/pthread_join.c | 36 ++++++++++++++-- tests/other/test_pthread_self_join_detach.c | 11 +++++ 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/library_pthread.js b/src/library_pthread.js index 3d6b6d3394dd4..1b01fdbb11f7a 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -879,42 +879,14 @@ var LibraryPThread = { #endif }, - _emscripten_do_pthread_join__deps: ['$cleanupThread', 'pthread_testcancel', 'emscripten_main_thread_process_queued_calls', 'emscripten_futex_wait', 'pthread_self', 'emscripten_main_browser_thread_id', + __pthread_join_js__deps: ['$cleanupThread', 'pthread_testcancel', 'emscripten_main_thread_process_queued_calls', 'emscripten_futex_wait', 'pthread_self', 'emscripten_main_browser_thread_id', #if ASSERTIONS || IN_TEST_HARNESS || !MINIMAL_RUNTIME || !ALLOW_BLOCKING_ON_MAIN_THREAD 'emscripten_check_blocking_allowed' #endif ], - _emscripten_do_pthread_join: function(thread, status, block) { - if (!thread) { - err('pthread_join attempted on a null thread pointer!'); - return {{{ cDefine('ESRCH') }}}; - } - var self = {{{ makeGetValue('thread', C_STRUCTS.pthread.self, 'i32') }}}; - if (self !== thread) { - err('pthread_join attempted on thread 0x' + thread.toString(16) + ', which does not point to a valid thread, or does not exist anymore!'); - return {{{ cDefine('ESRCH') }}}; - } - var detach_state = Atomics.load(HEAPU32, (thread + {{{ C_STRUCTS.pthread.detach_state }}}) >> 2); - if (detach_state == {{{ cDefine('DT_DETACHED') }}}) { - err('Attempted to join thread 0x' + thread.toString(16) + ', which was already detached!'); - return {{{ cDefine('EINVAL') }}}; // The thread is already detached, can no longer join it! - } - - if (detach_state == {{{ cDefine('DT_EXITED') }}}) { - err('Attempted to join thread 0x' + thread.toString(16) + ', which was already joined!'); - return {{{ cDefine('EINVAL') }}}; - } - if (ENVIRONMENT_IS_PTHREAD && _pthread_self() == thread) { - err('PThread ' + thread + ' is attempting to join to itself!'); - return {{{ cDefine('EDEADLK') }}}; - } - else if (!ENVIRONMENT_IS_PTHREAD && _emscripten_main_browser_thread_id() == thread) { - err('Main thread ' + thread + ' is attempting to join to itself!'); - return {{{ cDefine('EDEADLK') }}}; - } - + __pthread_join_js: function(thread, status, tryjoin) { #if ASSERTIONS || IN_TEST_HARNESS || !MINIMAL_RUNTIME || !ALLOW_BLOCKING_ON_MAIN_THREAD - if (block) { + if (!tryjoin) { _emscripten_check_blocking_allowed(); } #endif @@ -932,9 +904,6 @@ var LibraryPThread = { else postMessage({ 'cmd': 'cleanupThread', 'thread': thread }); return 0; } - if (!block) { - return {{{ cDefine('EBUSY') }}}; - } _pthread_testcancel(); // In main runtime thread (the thread that initialized the Emscripten C // runtime and launched main()), assist pthreads in performing operations @@ -944,16 +913,6 @@ var LibraryPThread = { } }, - __pthread_join_js__deps: ['_emscripten_do_pthread_join'], - __pthread_join_js: function(thread, status) { - return __emscripten_do_pthread_join(thread, status, true); - }, - - pthread_tryjoin_np__deps: ['_emscripten_do_pthread_join'], - pthread_tryjoin_np: function(thread, status) { - return __emscripten_do_pthread_join(thread, status, false); - }, - pthread_kill__deps: ['$killThread', 'emscripten_main_browser_thread_id'], pthread_kill: function(thread, signal) { if (signal < 0 || signal >= 65/*_NSIG*/) return {{{ cDefine('EINVAL') }}}; diff --git a/system/lib/pthread/pthread_join.c b/system/lib/pthread/pthread_join.c index b7883d022b3c4..ca4f93e155bb6 100644 --- a/system/lib/pthread/pthread_join.c +++ b/system/lib/pthread/pthread_join.c @@ -8,9 +8,39 @@ #include "pthread_impl.h" #include -extern int __pthread_join_js(pthread_t thread, void **retval); -int __pthread_join(pthread_t thread, void **retval) { - return __pthread_join_js(thread, retval); +extern int __pthread_join_js(pthread_t t, void **res, int tryjoin); + +static int __pthread_join_internal(pthread_t t, void **res, int tryjoin) { + if (t->self != t) { + // attempt to join a thread which does not point to a valid thread, or does + // not exist anymore. + return ESRCH; + } + // TODO(sbc): IIUC __pthread_join_js currently doesn't handle the case + // when the thread becomes detached/joined *during* the join. This pre-check + // can potentially be removed once it does. + int state = t->detach_state; + if (state == DT_DETACHED || state == DT_EXITED) { + // The thread is detached or already joined, and therefore not joinable + return EINVAL; + } + if (t == __pthread_self()) { + // thread is attempting to join to itself. + return EDEADLK; + } + return __pthread_join_js(t, res, tryjoin); +} + +int __pthread_join(pthread_t t, void **res) { + return __pthread_join_internal(t, res, 0); } + +// Taken directly from system/lib/libc/musl/src/thread/pthread_join.c +int __pthread_tryjoin_np(pthread_t t, void **res) +{ + return t->detach_state==DT_JOINABLE ? EBUSY : __pthread_join_internal(t, res, 1); +} + weak_alias(__pthread_join, emscripten_builtin_pthread_join); +weak_alias(__pthread_tryjoin_np, pthread_tryjoin_np); weak_alias(__pthread_join, pthread_join); diff --git a/tests/other/test_pthread_self_join_detach.c b/tests/other/test_pthread_self_join_detach.c index 9c0496b827768..7d4293b76dfde 100644 --- a/tests/other/test_pthread_self_join_detach.c +++ b/tests/other/test_pthread_self_join_detach.c @@ -4,14 +4,20 @@ #include #include +#ifdef __EMSCRIPTEN__ #include +#endif int main() { /* * When running in PROXY_TO_PTHREAD mode the main thread * is already detached */ +#ifdef __EMSCRIPTEN__ int is_detached = !emscripten_is_main_browser_thread(); +#else + int is_detached = 0; +#endif pthread_t self = pthread_self(); /* @@ -20,6 +26,7 @@ int main() { * detached */ int ret = pthread_join(self, NULL); + printf("pthread_join -> %s\n", strerror(ret)); if (is_detached) { assert(ret == EINVAL); } else { @@ -38,6 +45,10 @@ int main() { assert(ret == 0); } + ret = pthread_join(self, NULL); + printf("pthread_join -> %s\n", strerror(ret)); + assert(ret == EINVAL); + puts("passed"); return 0;