Skip to content

Commit adb639c

Browse files
authored
[browser][MT] invocation of user JS in UI thread till next event loop tick (#100040)
1 parent 310b824 commit adb639c

File tree

13 files changed

+133
-27
lines changed

13 files changed

+133
-27
lines changed

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerArgument.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ internal struct JSMarshalerArgumentImpl
6868

6969
[FieldOffset(24)]
7070
internal IntPtr CallerNativeTID;
71+
72+
[FieldOffset(28)]
73+
internal IntPtr SyncDoneSemaphorePtr;
7174
#endif
7275
}
7376

src/mono/browser/runtime/cancelable-promise.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { compareExchangeI32, forceThreadMemoryViewRefresh } from "./memory";
1111
import { mono_log_debug } from "./logging";
1212
import { complete_task } from "./managed-exports";
1313
import { marshal_cs_object_to_cs } from "./marshal-to-cs";
14+
import { invoke_later_when_on_ui_thread_async } from "./invoke-js";
1415

1516
export const _are_promises_supported = ((typeof Promise === "object") || (typeof Promise === "function")) && (typeof Promise.resolve === "function");
1617

@@ -35,6 +36,11 @@ export function wrap_as_cancelable<T>(inner: Promise<T>): ControllablePromise<T>
3536
}
3637

3738
export function mono_wasm_cancel_promise(task_holder_gc_handle: GCHandle): void {
39+
// cancelation should not arrive earlier than the promise created by marshaling in mono_wasm_invoke_jsimport_MT
40+
invoke_later_when_on_ui_thread_async(() => mono_wasm_cancel_promise_impl(task_holder_gc_handle));
41+
}
42+
43+
export function mono_wasm_cancel_promise_impl(task_holder_gc_handle: GCHandle): void {
3844
if (!loaderHelpers.is_runtime_running()) {
3945
mono_log_debug("This promise can't be canceled, mono runtime already exited.");
4046
return;

src/mono/browser/runtime/corebindings.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ void mono_wasm_cancel_promise_post (pthread_t target_tid, int task_holder_gc_han
4444
extern void mono_wasm_install_js_worker_interop (int context_gc_handle);
4545
void mono_wasm_install_js_worker_interop_wrapper (int context_gc_handle, void* beforeSyncJSImport, void* afterSyncJSImport);
4646
extern void mono_wasm_uninstall_js_worker_interop ();
47-
extern void mono_wasm_invoke_jsimport (void* signature, void* args);
47+
extern void mono_wasm_invoke_jsimport_MT (void* signature, void* args);
4848
void mono_wasm_invoke_jsimport_async_post (pthread_t target_tid, void* signature, void* args);
4949
void mono_wasm_invoke_jsimport_sync_send (pthread_t target_tid, void* signature, void* args);
5050
void mono_wasm_invoke_js_function_send (pthread_t target_tid, int function_js_handle, void *args);
5151
extern void mono_threads_wasm_async_run_in_target_thread_vi (pthread_t target_thread, void (*func) (gpointer), gpointer user_data1);
5252
extern void mono_threads_wasm_async_run_in_target_thread_vii (pthread_t target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2);
53-
extern void mono_threads_wasm_sync_run_in_target_thread_vii (pthread_t target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2);
53+
extern void mono_threads_wasm_sync_run_in_target_thread_vii (pthread_t target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer args);
5454
#else
5555
extern void mono_wasm_bind_js_import (void *signature, int *is_exception, MonoObject **result);
5656
extern void mono_wasm_invoke_jsimport_ST (int function_handle, void *args);
@@ -80,7 +80,7 @@ void bindings_initialize_internals (void)
8080
mono_add_internal_call ("Interop/Runtime::ResolveOrRejectPromisePost", mono_wasm_resolve_or_reject_promise_post);
8181
mono_add_internal_call ("Interop/Runtime::InstallWebWorkerInterop", mono_wasm_install_js_worker_interop_wrapper);
8282
mono_add_internal_call ("Interop/Runtime::UninstallWebWorkerInterop", mono_wasm_uninstall_js_worker_interop);
83-
mono_add_internal_call ("Interop/Runtime::InvokeJSImportSync", mono_wasm_invoke_jsimport);
83+
mono_add_internal_call ("Interop/Runtime::InvokeJSImportSync", mono_wasm_invoke_jsimport_MT);
8484
mono_add_internal_call ("Interop/Runtime::InvokeJSImportSyncSend", mono_wasm_invoke_jsimport_sync_send);
8585
mono_add_internal_call ("Interop/Runtime::InvokeJSImportAsyncPost", mono_wasm_invoke_jsimport_async_post);
8686
mono_add_internal_call ("Interop/Runtime::InvokeJSFunctionSend", mono_wasm_invoke_js_function_send);
@@ -285,13 +285,13 @@ void mono_wasm_cancel_promise_post (pthread_t target_tid, int task_holder_gc_han
285285
// async
286286
void mono_wasm_invoke_jsimport_async_post (pthread_t target_tid, void* signature, void* args)
287287
{
288-
mono_threads_wasm_async_run_in_target_thread_vii (target_tid, (void (*) (gpointer, gpointer))mono_wasm_invoke_jsimport, (gpointer)signature, (gpointer)args);
288+
mono_threads_wasm_async_run_in_target_thread_vii (target_tid, (void (*) (gpointer, gpointer))mono_wasm_invoke_jsimport_MT, (gpointer)signature, (gpointer)args);
289289
}
290290

291291
// sync
292292
void mono_wasm_invoke_jsimport_sync_send (pthread_t target_tid, void* signature, void* args)
293293
{
294-
mono_threads_wasm_sync_run_in_target_thread_vii (target_tid, (void (*) (gpointer, gpointer))mono_wasm_invoke_jsimport, (gpointer)signature, (gpointer)args);
294+
mono_threads_wasm_sync_run_in_target_thread_vii (target_tid, (void (*) (gpointer, gpointer))mono_wasm_invoke_jsimport_MT, (gpointer)signature, (gpointer)args);
295295
}
296296

297297
// sync

src/mono/browser/runtime/cwraps.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const threading_cwraps: SigLine[] = WasmEnableThreads ? [
3333
[true, "mono_wasm_register_ui_thread", "void", []],
3434
[true, "mono_wasm_register_io_thread", "void", []],
3535
[true, "mono_wasm_print_thread_dump", "void", []],
36+
[true, "mono_threads_wasm_sync_run_in_target_thread_done", "void", ["number"]],
3637
] : [];
3738

3839
// when the method is assigned/cached at usage, instead of being invoked directly from cwraps, it can't be marked lazy, because it would be re-bound on each call
@@ -156,6 +157,7 @@ export interface t_ThreadingCwraps {
156157
mono_wasm_register_ui_thread(): void;
157158
mono_wasm_register_io_thread(): void;
158159
mono_wasm_print_thread_dump(): void;
160+
mono_threads_wasm_sync_run_in_target_thread_done(sem: VoidPtr): void;
159161
}
160162

161163
export interface t_ProfilerCwraps {

src/mono/browser/runtime/driver.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ mono_wasm_invoke_jsexport (MonoMethod *method, void* args)
256256
#ifndef DISABLE_THREADS
257257

258258
extern void mono_threads_wasm_async_run_in_target_thread_vii (void* target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2);
259-
extern void mono_threads_wasm_sync_run_in_target_thread_vii (void* target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2);
259+
extern void mono_threads_wasm_sync_run_in_target_thread_vii (void* target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer args);
260260
extern void mono_print_thread_dump (void *sigctx);
261261

262262
EMSCRIPTEN_KEEPALIVE void
@@ -271,7 +271,7 @@ mono_wasm_invoke_jsexport_async_post_cb (MonoMethod *method, void* args)
271271
{
272272
mono_wasm_invoke_jsexport (method, args);
273273
if (args) {
274-
MonoBoolean *is_receiver_should_free = (MonoBoolean *)(args + 20/*JSMarshalerArgumentOffsets.ReceiverShouldFree*/);
274+
MonoBoolean *is_receiver_should_free = (MonoBoolean *)(((char *) args) + 20/*JSMarshalerArgumentOffsets.ReceiverShouldFree*/);
275275
if(*is_receiver_should_free != 0){
276276
free (args);
277277
}
@@ -303,7 +303,7 @@ mono_wasm_invoke_jsexport_sync (MonoMethod *method, void* args)
303303
EMSCRIPTEN_KEEPALIVE void
304304
mono_wasm_invoke_jsexport_sync_send (void* target_thread, MonoMethod *method, void* args /*JSMarshalerArguments*/)
305305
{
306-
mono_threads_wasm_sync_run_in_target_thread_vii(target_thread, (void (*)(gpointer, gpointer))mono_wasm_invoke_jsexport_sync, method, args);
306+
mono_threads_wasm_sync_run_in_target_thread_vii (target_thread, (void (*)(gpointer, gpointer))mono_wasm_invoke_jsexport_sync, method, args);
307307
}
308308

309309
#endif /* DISABLE_THREADS */

src/mono/browser/runtime/exports-binding.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads";
55

66
import { mono_wasm_debugger_log, mono_wasm_add_dbg_command_received, mono_wasm_set_entrypoint_breakpoint, mono_wasm_fire_debugger_agent_message_with_data, mono_wasm_fire_debugger_agent_message_with_data_to_pause } from "./debug";
77
import { mono_wasm_release_cs_owned_object } from "./gc-handles";
8-
import { mono_wasm_bind_js_import, mono_wasm_invoke_js_function, mono_wasm_invoke_jsimport, mono_wasm_invoke_jsimport_ST } from "./invoke-js";
8+
import { mono_wasm_bind_js_import, mono_wasm_invoke_js_function, mono_wasm_invoke_jsimport_MT, mono_wasm_invoke_jsimport_ST } from "./invoke-js";
99
import { mono_interp_tier_prepare_jiterpreter, mono_jiterp_free_method_data_js } from "./jiterpreter";
1010
import { mono_interp_jit_wasm_entry_trampoline, mono_interp_record_interp_entry } from "./jiterpreter-interp-entry";
1111
import { mono_interp_jit_wasm_jit_call_trampoline, mono_interp_invoke_wasm_jit_call_trampoline, mono_interp_flush_jitcall_queue } from "./jiterpreter-jit-call";
@@ -55,7 +55,7 @@ export const mono_wasm_threads_imports = !WasmEnableThreads ? [] : [
5555
// corebindings.c
5656
mono_wasm_install_js_worker_interop,
5757
mono_wasm_uninstall_js_worker_interop,
58-
mono_wasm_invoke_jsimport,
58+
mono_wasm_invoke_jsimport_MT,
5959
];
6060

6161
export const mono_wasm_imports = [

src/mono/browser/runtime/invoke-js.ts

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads";
55
import BuildConfiguration from "consts:configuration";
66

77
import { marshal_exception_to_cs, bind_arg_marshal_to_cs } from "./marshal-to-cs";
8-
import { get_signature_argument_count, bound_js_function_symbol, get_sig, get_signature_version, get_signature_type, imported_js_function_symbol, get_signature_handle, get_signature_function_name, get_signature_module_name, is_receiver_should_free, get_caller_native_tid } from "./marshal";
8+
import { get_signature_argument_count, bound_js_function_symbol, get_sig, get_signature_version, get_signature_type, imported_js_function_symbol, get_signature_handle, get_signature_function_name, get_signature_module_name, is_receiver_should_free, get_caller_native_tid, get_sync_done_semaphore_ptr } from "./marshal";
99
import { setI32_unchecked, receiveWorkerHeapViews, forceThreadMemoryViewRefresh } from "./memory";
1010
import { stringToMonoStringRoot } from "./strings";
1111
import { MonoObject, MonoObjectRef, JSFunctionSignature, JSMarshalerArguments, WasmRoot, BoundMarshalerToJs, JSFnHandle, BoundMarshalerToCs, JSHandle, MarshalerType } from "./types/internal";
@@ -17,6 +17,8 @@ import { mono_log_debug, mono_wasm_symbolicate_string } from "./logging";
1717
import { mono_wasm_get_jsobj_from_js_handle } from "./gc-handles";
1818
import { endMeasure, MeasuredBlock, startMeasure } from "./profiler";
1919
import { wrap_as_cancelable_promise } from "./cancelable-promise";
20+
import { threads_c_functions as tcwraps } from "./cwraps";
21+
import { monoThreadInfo } from "./pthreads";
2022

2123
export const js_import_wrapper_by_fn_handle: Function[] = <any>[null];// 0th slot is dummy, main thread we free them on shutdown. On web worker thread we free them when worker is detached.
2224

@@ -35,7 +37,7 @@ export function mono_wasm_bind_js_import(signature: JSFunctionSignature, is_exce
3537
}
3638
}
3739

38-
export function mono_wasm_invoke_jsimport(signature: JSFunctionSignature, args: JSMarshalerArguments) {
40+
export function mono_wasm_invoke_jsimport_MT(signature: JSFunctionSignature, args: JSMarshalerArguments) {
3941
if (!WasmEnableThreads) return;
4042
assert_js_interop();
4143

@@ -137,7 +139,6 @@ function bind_js_import(signature: JSFunctionSignature): Function {
137139
forceThreadMemoryViewRefresh();
138140
bound_fn(args);
139141
}
140-
141142
function sync_bound_fn(args: JSMarshalerArguments): void {
142143
const previous = runtimeHelpers.isPendingSynchronousCall;
143144
try {
@@ -150,14 +151,29 @@ function bind_js_import(signature: JSFunctionSignature): Function {
150151
runtimeHelpers.isPendingSynchronousCall = previous;
151152
}
152153
}
154+
function async_bound_fn_ui(args: JSMarshalerArguments): void {
155+
invoke_later_when_on_ui_thread_async(() => async_bound_fn(args));
156+
}
157+
function sync_bound_fn_ui(args: JSMarshalerArguments): void {
158+
invoke_later_when_on_ui_thread_sync(() => sync_bound_fn(args), args);
159+
}
153160

154161
let wrapped_fn: WrappedJSFunction = bound_fn;
155162
if (WasmEnableThreads) {
156-
if (is_async || is_discard_no_wait) {
157-
wrapped_fn = async_bound_fn;
158-
}
159-
else {
160-
wrapped_fn = sync_bound_fn;
163+
if (monoThreadInfo.isUI) {
164+
if (is_async || is_discard_no_wait) {
165+
wrapped_fn = async_bound_fn_ui;
166+
}
167+
else {
168+
wrapped_fn = sync_bound_fn_ui;
169+
}
170+
} else {
171+
if (is_async || is_discard_no_wait) {
172+
wrapped_fn = async_bound_fn;
173+
}
174+
else {
175+
wrapped_fn = sync_bound_fn;
176+
}
161177
}
162178
}
163179

@@ -337,6 +353,10 @@ type BindingClosure = {
337353
}
338354

339355
export function mono_wasm_invoke_js_function(bound_function_js_handle: JSHandle, args: JSMarshalerArguments): void {
356+
invoke_later_when_on_ui_thread_sync(() => mono_wasm_invoke_js_function_impl(bound_function_js_handle, args), args);
357+
}
358+
359+
export function mono_wasm_invoke_js_function_impl(bound_function_js_handle: JSHandle, args: JSMarshalerArguments): void {
340360
loaderHelpers.assert_runtime_running();
341361
const bound_fn = mono_wasm_get_jsobj_from_js_handle(bound_function_js_handle);
342362
mono_assert(bound_fn && typeof (bound_fn) === "function" && bound_fn[bound_js_function_symbol], () => `Bound function handle expected ${bound_function_js_handle}`);
@@ -493,3 +513,29 @@ export function assert_c_interop(): void {
493513
mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "The runtime must be initialized.");
494514
}
495515
}
516+
517+
// make sure we are not blocking em_task_queue_execute up the call stack
518+
// so that when we call back to managed, the FS calls could still be processed by the UI thread
519+
// see also emscripten_yield which can process the FS calls inside the spin wait
520+
export function invoke_later_when_on_ui_thread_sync(fn: Function, args: JSMarshalerArguments) {
521+
if (WasmEnableThreads && monoThreadInfo.isUI) {
522+
Module.safeSetTimeout(() => {
523+
fn();
524+
// see also mono_threads_wasm_sync_run_in_target_thread_vii_cb
525+
const done_semaphore = get_sync_done_semaphore_ptr(args);
526+
tcwraps.mono_threads_wasm_sync_run_in_target_thread_done(done_semaphore);
527+
}, 0);
528+
} else {
529+
fn();
530+
}
531+
}
532+
533+
// make sure we are not blocking em_task_queue_execute up the call stack
534+
// so that when we call back to managed, the FS calls could still be processed by the UI thread
535+
export function invoke_later_when_on_ui_thread_async(fn: Function) {
536+
if (WasmEnableThreads && monoThreadInfo.isUI) {
537+
Module.safeSetTimeout(fn, 0);
538+
} else {
539+
fn();
540+
}
541+
}

src/mono/browser/runtime/marshal-to-js.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory";
2424
import { call_delegate } from "./managed-exports";
2525
import { gc_locked } from "./gc-lock";
2626
import { mono_log_debug } from "./logging";
27+
import { invoke_later_when_on_ui_thread_async } from "./invoke-js";
2728

2829
export function initialize_marshalers_to_js(): void {
2930
if (cs_to_js_marshalers.size == 0) {
@@ -338,6 +339,10 @@ function create_task_holder(res_converter?: MarshalerToJs) {
338339
}
339340

340341
export function mono_wasm_resolve_or_reject_promise(args: JSMarshalerArguments): void {
342+
// rejection/resolution should not arrive earlier than the promise created by marshaling in mono_wasm_invoke_jsimport_MT
343+
invoke_later_when_on_ui_thread_async(() => mono_wasm_resolve_or_reject_promise_impl(args));
344+
}
345+
export function mono_wasm_resolve_or_reject_promise_impl(args: JSMarshalerArguments): void {
341346
if (!loaderHelpers.is_runtime_running()) {
342347
mono_log_debug("This promise resolution/rejection can't be propagated to managed code, mono runtime already exited.");
343348
return;

src/mono/browser/runtime/marshal.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles"
77
import { Module, loaderHelpers, mono_assert, runtimeHelpers } from "./globals";
88
import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8, localHeapViewF64, localHeapViewI32, localHeapViewU8, _zero_region, getB32, setB32, forceThreadMemoryViewRefresh } from "./memory";
99
import { mono_wasm_new_external_root } from "./roots";
10-
import { GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType, PThreadPtr, PThreadPtrNull } from "./types/internal";
10+
import { GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType, PThreadPtr, PThreadPtrNull, VoidPtrNull } from "./types/internal";
1111
import { TypedArray, VoidPtr } from "./types/emscripten";
1212
import { utf16ToString } from "./strings";
1313
import { get_managed_stack_trace } from "./managed-exports";
@@ -39,6 +39,7 @@ const enum JSMarshalerArgumentOffsets {
3939
ContextHandle = 16,
4040
ReceiverShouldFree = 20,
4141
CallerNativeTID = 24,
42+
SyncDoneSemaphorePtr = 28,
4243
}
4344
export const JSMarshalerTypeSize = 32;
4445
// keep in sync with JSFunctionBinding.JSBindingType
@@ -91,6 +92,12 @@ export function is_receiver_should_free(args: JSMarshalerArguments): boolean {
9192
return getB32(<any>args + JSMarshalerArgumentOffsets.ReceiverShouldFree);
9293
}
9394

95+
export function get_sync_done_semaphore_ptr(args: JSMarshalerArguments): VoidPtr {
96+
if (!WasmEnableThreads) return VoidPtrNull;
97+
mono_assert(args, "Null args");
98+
return getI32(<any>args + JSMarshalerArgumentOffsets.SyncDoneSemaphorePtr) as any;
99+
}
100+
94101
export function get_caller_native_tid(args: JSMarshalerArguments): PThreadPtr {
95102
if (!WasmEnableThreads) return PThreadPtrNull;
96103
mono_assert(args, "Null args");

src/mono/mono/utils/mono-threads-wasm.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -660,18 +660,33 @@ mono_threads_wasm_async_run_in_target_thread_vii (pthread_t target_thread, void
660660
emscripten_dispatch_to_thread_async (target_thread, EM_FUNC_SIG_VII, func, NULL, user_data1, user_data2);
661661
}
662662

663-
static void mono_threads_wasm_sync_run_in_target_thread_vii_cb (MonoCoopSem *done, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2)
663+
static void mono_threads_wasm_sync_run_in_target_thread_vii_cb (MonoCoopSem *done, void (*func) (gpointer, gpointer), gpointer user_data1, void* args)
664+
{
665+
// in UI thread we postpone the execution via safeSetTimeout so that emscripten_proxy_execute_queue is not blocked by this call
666+
// see invoke_later_on_ui_thread
667+
if (mono_threads_wasm_is_ui_thread()) {
668+
MonoCoopSem **semPtrPtr = (MonoCoopSem **)(((char *) args) + 28/*JSMarshalerArgumentOffsets.SyncDoneSemaphorePtr*/);
669+
*semPtrPtr = done;
670+
func (user_data1, args);
671+
}
672+
else {
673+
func (user_data1, args);
674+
mono_coop_sem_post (done);
675+
}
676+
}
677+
678+
EMSCRIPTEN_KEEPALIVE void
679+
mono_threads_wasm_sync_run_in_target_thread_done (MonoCoopSem *sem)
664680
{
665-
func (user_data1, user_data2);
666-
mono_coop_sem_post (done);
681+
mono_coop_sem_post (sem);
667682
}
668683

669684
void
670-
mono_threads_wasm_sync_run_in_target_thread_vii (pthread_t target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2)
685+
mono_threads_wasm_sync_run_in_target_thread_vii (pthread_t target_thread, void (*func) (gpointer, gpointer), gpointer user_data1, gpointer args)
671686
{
672687
MonoCoopSem sem;
673688
mono_coop_sem_init (&sem, 0);
674-
emscripten_dispatch_to_thread_async (target_thread, EM_FUNC_SIG_VIIII, mono_threads_wasm_sync_run_in_target_thread_vii_cb, NULL, &sem, func, user_data1, user_data2);
689+
emscripten_dispatch_to_thread_async (target_thread, EM_FUNC_SIG_VIIII, mono_threads_wasm_sync_run_in_target_thread_vii_cb, NULL, &sem, func, user_data1, args);
675690

676691
MONO_ENTER_GC_UNSAFE;
677692
mono_coop_sem_wait (&sem, MONO_SEM_FLAGS_NONE);

0 commit comments

Comments
 (0)