From 6a590dce8c88214ae8f8cda49f0fbda0b7762d78 Mon Sep 17 00:00:00 2001 From: Luigi Cruz Date: Sun, 24 Jan 2021 17:58:54 -0300 Subject: [PATCH 1/6] add synchronous call --- system/include/emscripten/threading.h | 4 ++++ system/lib/pthread/library_pthread.c | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/system/include/emscripten/threading.h b/system/include/emscripten/threading.h index 14a2d8890dd82..bb3bec04370f9 100644 --- a/system/include/emscripten/threading.h +++ b/system/include/emscripten/threading.h @@ -346,6 +346,10 @@ int _emscripten_call_on_thread(int force_async, pthread_t target_thread, EM_FUNC // but may be simpler to reason about in some cases. #define emscripten_dispatch_to_thread_async(target_thread, sig, func_ptr, satellite, ...) _emscripten_call_on_thread(1, (target_thread), (sig), (void*)(func_ptr), (satellite),##__VA_ARGS__) +// Similar to emscripten_dispatch_to_thread, but always runs the +// function synchronously, even if on the same thread. +#define emscripten_dispatch_to_thread_sync(target_thread, sig, func_ptr, satellite, ...) _emscripten_call_on_thread(2, (target_thread), (sig), (void*)(func_ptr), (satellite),##__VA_ARGS__) + // Returns 1 if the current thread is the thread that hosts the Emscripten runtime. int emscripten_is_main_runtime_thread(void); diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 8b35bfd6c4457..cee5d85ffdbc9 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -453,8 +453,8 @@ pthread_t emscripten_main_browser_thread_id() { return main_browser_thread_id_; } -int _emscripten_do_dispatch_to_thread( - pthread_t target_thread, em_queued_call* call) { +int _emscripten_do_dispatch_to_thread_global( + pthread_t target_thread, em_queued_call* call, int drop) { assert(call); // #if PTHREADS_DEBUG // TODO: Create a debug version of pthreads library @@ -492,7 +492,7 @@ int _emscripten_do_dispatch_to_thread( // If queue of the main browser thread is full, then we wait. (never drop messages for the main // browser thread) - if (target_thread == emscripten_main_browser_thread_id()) { + if (target_thread == emscripten_main_browser_thread_id() || drop == 0) { emscripten_futex_wait((void*)&q->call_queue_head, head, INFINITY); pthread_mutex_lock(&call_queue_lock); head = emscripten_atomic_load_u32((void*)&q->call_queue_head); @@ -531,6 +531,11 @@ int _emscripten_do_dispatch_to_thread( return 0; } +int _emscripten_do_dispatch_to_thread( + pthread_t target_thread, em_queued_call* call) { + return _emscripten_do_dispatch_to_thread_global(target_thread, call, 1); +} + void emscripten_async_run_in_main_thread(em_queued_call* call) { _emscripten_do_dispatch_to_thread(emscripten_main_browser_thread_id(), call); } @@ -907,13 +912,20 @@ int _emscripten_call_on_thread( q->calleeDelete = 1; // The called function will not be async if we are on the same thread; force // async if the user asked for that. - if (forceAsync) { + if (forceAsync == 1) { EM_ASM({ setTimeout(function() { __emscripten_do_dispatch_to_thread($0, $1); }, 0); }, targetThread, q); return 0; + } else if (forceAsync == 2) { + q->calleeDelete = 0; + _emscripten_do_dispatch_to_thread_global(targetThread, q, 0); + emscripten_wait_for_call_v(q, INFINITY); + int res = q->returnValue.i; + em_queued_call_free(q); + return res; } else { return _emscripten_do_dispatch_to_thread(targetThread, q); } From df341373cb5c3240ebe037736263e954d278eff0 Mon Sep 17 00:00:00 2001 From: Luigi Cruz Date: Wed, 10 Feb 2021 21:41:07 -0300 Subject: [PATCH 2/6] change forceAsync to dispatchMode --- system/lib/pthread/library_pthread.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index cee5d85ffdbc9..3db0d86adf934 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -866,8 +866,11 @@ em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_( } int _emscripten_call_on_thread( - int forceAsync, + int dispatchMode, pthread_t targetThread, EM_FUNC_SIGNATURE sig, void* func_ptr, void* satellite, ...) { + // dispatchMode==0 Synchronous if in the same thread_id, otherwise asynchronous. + // dispatchMode==1 Force asynchronous call even if in the same thread_id. + // dispatchMode==2 Always force a synchronous call. int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig); em_queued_call* q = em_queued_call_malloc(); assert(q); @@ -912,14 +915,14 @@ int _emscripten_call_on_thread( q->calleeDelete = 1; // The called function will not be async if we are on the same thread; force // async if the user asked for that. - if (forceAsync == 1) { + if (dispatchMode == 1) { EM_ASM({ setTimeout(function() { __emscripten_do_dispatch_to_thread($0, $1); }, 0); }, targetThread, q); return 0; - } else if (forceAsync == 2) { + } else if (dispatchMode == 2) { q->calleeDelete = 0; _emscripten_do_dispatch_to_thread_global(targetThread, q, 0); emscripten_wait_for_call_v(q, INFINITY); From 49cb39f1afa69c327593633cf0b7820de8c58272 Mon Sep 17 00:00:00 2001 From: Luigi Cruz Date: Wed, 10 Feb 2021 21:58:26 -0300 Subject: [PATCH 3/6] Add name to AUTHORS list --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 8f9a5bb48c190..0d4f4babcf863 100644 --- a/AUTHORS +++ b/AUTHORS @@ -540,3 +540,4 @@ a license to everyone to use it as detailed in LICENSE.) * Raffaele Pertile * Patric Stout * Jinoh Kang +* Luigi F. Cruz From eb83b8373cf91136b34009cf7f90ec3c0e8af3ed Mon Sep 17 00:00:00 2001 From: Luigi Cruz Date: Thu, 11 Feb 2021 00:56:14 -0300 Subject: [PATCH 4/6] Add tests for emscripten_dispatch_to_thread_sync --- tests/pthread/call_sync.c | 39 +++++++++++++++++++++++++++++++++++++++ tests/test_browser.py | 4 ++++ 2 files changed, 43 insertions(+) create mode 100644 tests/pthread/call_sync.c diff --git a/tests/pthread/call_sync.c b/tests/pthread/call_sync.c new file mode 100644 index 0000000000000..149be5c73899f --- /dev/null +++ b/tests/pthread/call_sync.c @@ -0,0 +1,39 @@ +/* + * Copyright 2020 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +static _Atomic bool started = false; + +void *new_thread(void* ctx) { + started = true; + emscripten_exit_with_live_runtime(); + return NULL; +} + +int magic_number() { + assert(emscripten_main_browser_thread_id() != pthread_self()); + return 42; +} + +int main() { + pthread_t worker; + assert(pthread_create(&worker, NULL, new_thread, NULL) == 0); + while (!started) + emscripten_sleep(100); + + assert(emscripten_dispatch_to_thread_sync(worker, EM_FUNC_SIG_I, &magic_number, NULL) == 42); + +#ifdef REPORT_RESULT + REPORT_RESULT(1); +#endif +} diff --git a/tests/test_browser.py b/tests/test_browser.py index a6548a7c91318..6b9999de68aad 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3898,6 +3898,10 @@ def test_pthread_run_on_main_thread_flood(self): def test_pthread_call_async(self): self.btest(path_from_root('tests', 'pthread', 'call_async.c'), expected='1', args=['-s', 'USE_PTHREADS']) + @requires_threads + def test_pthread_call_sync(self): + self.btest(path_from_root('tests', 'pthread', 'call_sync.c'), expected='1', args=['-s', 'ASYNCIFY', '-s', 'USE_PTHREADS']) + # Test that it is possible to synchronously call a JavaScript function on the main thread and get a return value back. @requires_threads def test_pthread_call_sync_on_main_thread(self): From 1ff91c25600150098d386ebc8add6c15c56b9e2a Mon Sep 17 00:00:00 2001 From: Luigi Cruz Date: Thu, 11 Feb 2021 00:58:52 -0300 Subject: [PATCH 5/6] fix indentation --- tests/pthread/call_sync.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/pthread/call_sync.c b/tests/pthread/call_sync.c index 149be5c73899f..6527c77baa578 100644 --- a/tests/pthread/call_sync.c +++ b/tests/pthread/call_sync.c @@ -15,9 +15,9 @@ static _Atomic bool started = false; void *new_thread(void* ctx) { - started = true; - emscripten_exit_with_live_runtime(); - return NULL; + started = true; + emscripten_exit_with_live_runtime(); + return NULL; } int magic_number() { @@ -34,6 +34,6 @@ int main() { assert(emscripten_dispatch_to_thread_sync(worker, EM_FUNC_SIG_I, &magic_number, NULL) == 42); #ifdef REPORT_RESULT - REPORT_RESULT(1); + REPORT_RESULT(1); #endif } From 98325cc6480d756e1079b3e6060739ab050c0c4e Mon Sep 17 00:00:00 2001 From: Luigi Cruz Date: Sat, 1 May 2021 01:13:16 -0300 Subject: [PATCH 6/6] add missing functions --- .../metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs b/tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs index 17dedb5a5c6cd..c55297683aa73 100644 --- a/tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs +++ b/tests/other/metadce/minimal_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs @@ -12,6 +12,7 @@ $__wasm_init_memory $_do_call $_emscripten_call_on_thread $_emscripten_do_dispatch_to_thread +$_emscripten_do_dispatch_to_thread_global $_emscripten_thread_init $_main_thread $a_cas @@ -32,6 +33,7 @@ $emscripten_stack_set_limits $emscripten_sync_run_in_main_thread $emscripten_sync_run_in_main_thread $emscripten_tls_init +$emscripten_wait_for_call_v $free_tls $init_mparams $sbrk