Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
use simpler mono_wasm_schedule_synchronization_context instead of `…
…schedule_background_exec`

makes scheduling.ts ST only
  • Loading branch information
pavelsavara committed Mar 25, 2024
commit 3f030a1c989dfbe463b4b9c7513606cc511fe9ed
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ internal static unsafe partial class Runtime

#if FEATURE_WASM_MANAGED_THREADS
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void InstallWebWorkerInterop(nint proxyContextGCHandle, void* beforeSyncJSImport, void* afterSyncJSImport);
public static extern void InstallWebWorkerInterop(nint proxyContextGCHandle, void* beforeSyncJSImport, void* afterSyncJSImport, void* pumpHandler);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void UninstallWebWorkerInterop();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public static unsafe JSSynchronizationContext InstallWebWorkerInterop(bool isMai

Interop.Runtime.InstallWebWorkerInterop(proxyContext.ContextHandle,
(delegate* unmanaged[Cdecl]<JSMarshalerArgument*, void>)&JavaScriptExports.BeforeSyncJSExport,
(delegate* unmanaged[Cdecl]<JSMarshalerArgument*, void>)&JavaScriptExports.AfterSyncJSExport);
(delegate* unmanaged[Cdecl]<JSMarshalerArgument*, void>)&JavaScriptExports.AfterSyncJSExport,
(delegate* unmanaged[Cdecl]<void>)&PumpHandler);

return ctx;
}
Expand Down Expand Up @@ -170,7 +171,7 @@ private unsafe void ScheduleJSPump()
{
// While we COULD pump here, we don't want to. We want the pump to happen on the next event loop turn.
// Otherwise we could get a chain where a pump generates a new work item and that makes us pump again, forever.
TargetThreadScheduleBackgroundJob(ProxyContext.NativeTID, (delegate* unmanaged[Cdecl]<void>)&BackgroundJobHandler);
ScheduleSynchronizationContext(ProxyContext.NativeTID);
}

public override void Post(SendOrPostCallback d, object? state)
Expand Down Expand Up @@ -236,13 +237,13 @@ public override void Send(SendOrPostCallback d, object? state)
}

[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern unsafe void TargetThreadScheduleBackgroundJob(IntPtr targetTID, void* callback);
internal static extern unsafe void ScheduleSynchronizationContext(IntPtr targetTID);

#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
#pragma warning restore CS3016
// this callback will arrive on the target thread, called from mono_background_exec
private static void BackgroundJobHandler()
private static void PumpHandler()
{
var ctx = JSProxyContext.AssertIsInteropThread();
ctx.SynchronizationContext.Pump();
Expand Down Expand Up @@ -286,7 +287,7 @@ private void Pump()
}
catch (Exception e)
{
Environment.FailFast($"JSSynchronizationContext.BackgroundJobHandler failed, ManagedThreadId: {Environment.CurrentManagedThreadId}. {Environment.NewLine} {e.StackTrace}");
Environment.FailFast($"JSSynchronizationContext.Pump failed, ManagedThreadId: {Environment.CurrentManagedThreadId}. {Environment.NewLine} {e.StackTrace}");
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/mono/browser/runtime/corebindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void mono_wasm_resolve_or_reject_promise_post (pthread_t target_tid, void *args)
void mono_wasm_cancel_promise_post (pthread_t target_tid, int task_holder_gc_handle);

extern void mono_wasm_install_js_worker_interop (int context_gc_handle);
void mono_wasm_install_js_worker_interop_wrapper (int context_gc_handle, void* beforeSyncJSImport, void* afterSyncJSImport);
void mono_wasm_install_js_worker_interop_wrapper (int context_gc_handle, void* beforeSyncJSImport, void* afterSyncJSImport, void* pumpHandler);
extern void mono_wasm_uninstall_js_worker_interop ();
extern void mono_wasm_invoke_jsimport_MT (void* signature, void* args);
void mono_wasm_invoke_jsimport_async_post (pthread_t target_tid, void* signature, void* args);
Expand Down Expand Up @@ -256,11 +256,13 @@ void mono_wasm_get_assembly_export (char *assembly_name, char *namespace, char *

void* before_sync_js_import;
void* after_sync_js_import;
void* synchronization_context_pump_handler;

void mono_wasm_install_js_worker_interop_wrapper (int context_gc_handle, void* beforeSyncJSImport, void* afterSyncJSImport)
void mono_wasm_install_js_worker_interop_wrapper (int context_gc_handle, void* beforeSyncJSImport, void* afterSyncJSImport, void* pumpHandler)
{
before_sync_js_import = beforeSyncJSImport;
after_sync_js_import = afterSyncJSImport;
synchronization_context_pump_handler = pumpHandler;
mono_wasm_install_js_worker_interop (context_gc_handle);
}

Expand Down
2 changes: 2 additions & 0 deletions src/mono/browser/runtime/cwraps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const threading_cwraps: SigLine[] = WasmEnableThreads ? [
[true, "mono_wasm_register_ui_thread", "void", []],
[true, "mono_wasm_register_io_thread", "void", []],
[true, "mono_wasm_print_thread_dump", "void", []],
[true, "mono_wasm_synchronization_context_pump", "void", []],
[true, "mono_threads_wasm_sync_run_in_target_thread_done", "void", ["number"]],
] : [];

Expand Down Expand Up @@ -157,6 +158,7 @@ export interface t_ThreadingCwraps {
mono_wasm_register_ui_thread(): void;
mono_wasm_register_io_thread(): void;
mono_wasm_print_thread_dump(): void;
mono_wasm_synchronization_context_pump(): void;
mono_threads_wasm_sync_run_in_target_thread_done(sem: VoidPtr): void;
}

Expand Down
7 changes: 7 additions & 0 deletions src/mono/browser/runtime/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,10 @@ mono_wasm_invoke_jsexport_async_post (void* target_thread, MonoMethod *method, v


typedef void (*js_interop_event)(void* args);
typedef void (*sync_context_pump)(void);
extern js_interop_event before_sync_js_import;
extern js_interop_event after_sync_js_import;
extern sync_context_pump synchronization_context_pump_handler;

// this is running on the target thread
EMSCRIPTEN_KEEPALIVE void
Expand All @@ -306,6 +308,11 @@ mono_wasm_invoke_jsexport_sync_send (void* target_thread, MonoMethod *method, vo
mono_threads_wasm_sync_run_in_target_thread_vii (target_thread, (void (*)(gpointer, gpointer))mono_wasm_invoke_jsexport_sync, method, args);
}

EMSCRIPTEN_KEEPALIVE void mono_wasm_synchronization_context_pump (void)
{
synchronization_context_pump_handler ();
}

#endif /* DISABLE_THREADS */

EMSCRIPTEN_KEEPALIVE void
Expand Down
2 changes: 2 additions & 0 deletions src/mono/browser/runtime/exports-binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
mono_wasm_pthread_on_pthread_registered, mono_wasm_pthread_set_name, mono_wasm_install_js_worker_interop, mono_wasm_uninstall_js_worker_interop, mono_wasm_start_io_thread_async
} from "./pthreads";
import { mono_wasm_dump_threads } from "./pthreads/ui-thread";
import { mono_wasm_schedule_synchronization_context } from "./pthreads/shared";


// the JS methods would be visible to EMCC linker and become imports of the WASM module
Expand All @@ -44,6 +45,7 @@ export const mono_wasm_threads_imports = !WasmEnableThreads ? [] : [
mono_wasm_pthread_set_name,
mono_wasm_start_deputy_thread_async,
mono_wasm_start_io_thread_async,
mono_wasm_schedule_synchronization_context,

// mono-threads.c
mono_wasm_dump_threads,
Expand Down
13 changes: 13 additions & 0 deletions src/mono/browser/runtime/pthreads/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { set_thread_prefix } from "../logging";
import { bindings_init } from "../startup";
import { forceDisposeProxies } from "../gc-handles";
import { monoMessageSymbol, GCHandleNull, PThreadPtrNull, WorkerToMainMessageType } from "../types/internal";
import { threads_c_functions as tcwraps } from "../cwraps";

// A duplicate in loader/assets.ts
export const worker_empty_prefix = " - ";
Expand Down Expand Up @@ -106,6 +107,18 @@ export function update_thread_info(): void {
}
}

export function exec_synchronization_context_pump(): void {
if (!loaderHelpers.is_runtime_running()) {
return;
}
tcwraps.mono_wasm_synchronization_context_pump();
}

export function mono_wasm_schedule_synchronization_context(): void {
if (!WasmEnableThreads) return;
Module.safeSetTimeout(exec_synchronization_context_pump, 0);
}

export function mono_wasm_pthread_ptr(): PThreadPtr {
if (!WasmEnableThreads) return PThreadPtrNull;
return (<any>Module)["_pthread_self"]();
Expand Down
33 changes: 8 additions & 25 deletions src/mono/browser/runtime/scheduling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import WasmEnableThreads from "consts:wasmEnableThreads";

import cwraps from "./cwraps";
import { ENVIRONMENT_IS_WORKER, Module, loaderHelpers } from "./globals";
import { Module, loaderHelpers } from "./globals";
import { forceThreadMemoryViewRefresh } from "./memory";
import { is_thread_available } from "./pthreads";

let spread_timers_maximum = 0;
let pump_count = 0;

export function prevent_timer_throttling(): void {
if (WasmEnableThreads) return;
if (!loaderHelpers.isChromium) {
return;
}
Expand All @@ -30,55 +30,37 @@ export function prevent_timer_throttling(): void {
}

function prevent_timer_throttling_tick() {
if (WasmEnableThreads) return;
Module.maybeExit();
if (!loaderHelpers.is_runtime_running()) {
return;
}
if (WasmEnableThreads) {
forceThreadMemoryViewRefresh();
}
cwraps.mono_wasm_execute_timer();
pump_count++;
mono_background_exec_until_done();
}

function mono_background_exec_until_done() {
if (WasmEnableThreads) return;
Module.maybeExit();
if (!loaderHelpers.is_runtime_running()) {
return;
}
if (WasmEnableThreads) {
forceThreadMemoryViewRefresh();
}
while (pump_count > 0) {
--pump_count;
cwraps.mono_background_exec();
}
}

export function schedule_background_exec(): void {
if (WasmEnableThreads) return;
++pump_count;
let max_postpone_count = 10;
function postpone_schedule_background() {
if (max_postpone_count < 0 || is_thread_available()) {
Module.safeSetTimeout(mono_background_exec_until_done, 0);
} else {
max_postpone_count--;
Module.safeSetTimeout(postpone_schedule_background, 10);
}
}

if (WasmEnableThreads && !ENVIRONMENT_IS_WORKER) {
// give threads chance to load before we run more synchronous code on UI thread
postpone_schedule_background();
}
else {
Module.safeSetTimeout(mono_background_exec_until_done, 0);
}
Module.safeSetTimeout(mono_background_exec_until_done, 0);
}

let lastScheduledTimeoutId: any = undefined;
export function mono_wasm_schedule_timer(shortestDueTimeMs: number): void {
if (WasmEnableThreads) return;
if (lastScheduledTimeoutId) {
globalThis.clearTimeout(lastScheduledTimeoutId);
lastScheduledTimeoutId = undefined;
Expand All @@ -91,6 +73,7 @@ export function mono_wasm_schedule_timer(shortestDueTimeMs: number): void {
}

function mono_wasm_schedule_timer_tick() {
if (WasmEnableThreads) return;
Module.maybeExit();
if (WasmEnableThreads) {
forceThreadMemoryViewRefresh();
Expand Down
5 changes: 4 additions & 1 deletion src/mono/mono/mini/mini-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,10 @@ G_BEGIN_DECLS
EMSCRIPTEN_KEEPALIVE void mono_wasm_execute_timer (void);

//JS functions imported that we use
#ifdef DISABLE_THREADS
extern void mono_wasm_schedule_timer (int shortestDueTimeMs);
extern void mono_target_thread_schedule_synchronization_context(MonoNativeThreadId target_thread);
#endif // DISABLE_THREADS
G_END_DECLS

void mono_background_exec (void);
Expand Down Expand Up @@ -626,7 +629,7 @@ mono_arch_register_icall (void)
mono_add_internal_call_internal ("System.Threading.TimerQueue::MainThreadScheduleTimer", mono_wasm_main_thread_schedule_timer);
mono_add_internal_call_internal ("System.Threading.ThreadPool::MainThreadScheduleBackgroundJob", mono_main_thread_schedule_background_job);
#else
mono_add_internal_call_internal ("System.Runtime.InteropServices.JavaScript.JSSynchronizationContext::TargetThreadScheduleBackgroundJob", mono_target_thread_schedule_background_job);
mono_add_internal_call_internal ("System.Runtime.InteropServices.JavaScript.JSSynchronizationContext::ScheduleSynchronizationContext", mono_target_thread_schedule_synchronization_context);
#endif /* DISABLE_THREADS */
#endif /* HOST_BROWSER */
}
Expand Down
69 changes: 13 additions & 56 deletions src/mono/mono/utils/mono-threads-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,85 +346,31 @@ G_EXTERN_C
extern void schedule_background_exec (void);

// when this is called from ThreadPool, the cb would be System.Threading.ThreadPool.BackgroundJobHandler
// when this is called from JSSynchronizationContext, the cb would be System.Runtime.InteropServices.JavaScript.JSSynchronizationContext.BackgroundJobHandler
// when this is called from sgen it would be wrapper of sgen_perform_collection_inner
// when this is called from gc, it would be mono_runtime_do_background_work
#ifdef DISABLE_THREADS
void
mono_main_thread_schedule_background_job (background_job_cb cb)
{
g_assert (cb);
THREADS_DEBUG ("mono_main_thread_schedule_background_job2: thread %p queued job %p to current thread\n", (gpointer)pthread_self(), (gpointer) cb);
mono_current_thread_schedule_background_job (cb);
}
#endif /*DISABLE_THREADS*/

#ifndef DISABLE_THREADS
MonoNativeTlsKey jobs_key;
#else /* DISABLE_THREADS */
GSList *jobs;
#endif /* DISABLE_THREADS */

void
mono_current_thread_schedule_background_job (background_job_cb cb)
{
g_assert (cb);
#ifdef DISABLE_THREADS
THREADS_DEBUG ("mono_main_thread_schedule_background_job: thread %p queued job %p to current thread\n", (gpointer)pthread_self(), (gpointer) cb);

if (!jobs)
schedule_background_exec ();

if (!g_slist_find (jobs, (gconstpointer)cb))
jobs = g_slist_prepend (jobs, (gpointer)cb);

#else /*DISABLE_THREADS*/

GSList *jobs = mono_native_tls_get_value (jobs_key);
THREADS_DEBUG ("mono_current_thread_schedule_background_job1: thread %p queuing job %p into %p\n", (gpointer)pthread_self(), (gpointer) cb, (gpointer) jobs);
if (!jobs)
{
THREADS_DEBUG ("mono_current_thread_schedule_background_job2: thread %p calling schedule_background_exec before job %p\n", (gpointer)pthread_self(), (gpointer) cb);
schedule_background_exec ();
}

if (!g_slist_find (jobs, (gconstpointer)cb))
{
jobs = g_slist_prepend (jobs, (gpointer)cb);
mono_native_tls_set_value (jobs_key, jobs);
THREADS_DEBUG ("mono_current_thread_schedule_background_job3: thread %p queued job %p\n", (gpointer)pthread_self(), (gpointer) cb);
}

#endif /*DISABLE_THREADS*/
}

#ifndef DISABLE_THREADS
void
mono_target_thread_schedule_background_job (MonoNativeThreadId target_thread, background_job_cb cb)
{
THREADS_DEBUG ("worker %p queued job %p to worker %p \n", (gpointer)pthread_self(), (gpointer) cb, (gpointer) target_thread);
// NOTE: here the cb is [UnmanagedCallersOnly] which wraps it with MONO_ENTER_GC_UNSAFE/MONO_EXIT_GC_UNSAFE
mono_threads_wasm_async_run_in_target_thread_vi ((pthread_t) target_thread, (void*)mono_current_thread_schedule_background_job, (gpointer)cb);
}
#endif /*DISABLE_THREADS*/

G_EXTERN_C
EMSCRIPTEN_KEEPALIVE void
mono_background_exec (void);
GSList *jobs;

G_EXTERN_C
EMSCRIPTEN_KEEPALIVE void
mono_background_exec (void)
{
MONO_ENTER_GC_UNSAFE;
#ifdef DISABLE_THREADS
GSList *j = jobs, *cur;
jobs = NULL;
#else /* DISABLE_THREADS */
THREADS_DEBUG ("mono_background_exec on thread %p started\n", (gpointer)pthread_self());
GSList *jobs = mono_native_tls_get_value (jobs_key);
GSList *j = jobs, *cur;
mono_native_tls_set_value (jobs_key, NULL);
#endif /* DISABLE_THREADS */

for (cur = j; cur; cur = cur->next) {
background_job_cb cb = (background_job_cb)cur->data;
Expand All @@ -437,6 +383,17 @@ mono_background_exec (void)
MONO_EXIT_GC_UNSAFE;
}

#else /*DISABLE_THREADS*/

extern void mono_wasm_schedule_synchronization_context ();

void mono_target_thread_schedule_synchronization_context(MonoNativeThreadId target_thread)
{
emscripten_dispatch_to_thread_async ((pthread_t) target_thread, EM_FUNC_SIG_V, mono_wasm_schedule_synchronization_context, NULL);
}

#endif /*DISABLE_THREADS*/

gboolean
mono_threads_platform_is_main_thread (void)
{
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/utils/mono-threads-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ mono_wasm_atomic_wait_i32 (volatile int32_t *addr, int32_t expected, int32_t tim
return __builtin_wasm_memory_atomic_wait32((int32_t*)addr, expected, timeout_ns);
}

extern MonoNativeTlsKey jobs_key;
#else /* DISABLE_THREADS */
extern GSList *jobs;
#endif /* DISABLE_THREADS */
Expand Down
Loading