Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[browser][ST] avoid thread interruption checkpoint #112637

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
13 changes: 8 additions & 5 deletions src/mono/mono/metadata/marshal-lightweight.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static void
emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
{
// FIXME Put a boolean in MonoMethodBuilder instead.
if (strstr (mb->name, "mono_thread_interruption_checkpoint"))
if (mono_opt_wasm_disable_threads || strstr (mb->name, "mono_thread_interruption_checkpoint"))
return;

mono_marshal_shared_emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_interruption_checkpoint);
Expand All @@ -138,6 +138,9 @@ emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
static void
emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
{
if (mono_opt_wasm_disable_threads)
return;

mono_marshal_shared_emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise);
}

Expand Down Expand Up @@ -596,8 +599,8 @@ gc_safe_transition_builder_init (GCSafeTransitionBuilder *builder, MonoMethodBui
#ifndef DISABLE_THREADS
return TRUE;
#else
/* if we're in the AOT compiler, obey the --wasm-gc-safepoints option even if the AOT compiler doesn't have threads enabled */
return mono_opt_wasm_gc_safepoints;
/* if we're in the AOT compiler, obey the --wasm-disable-threads option even if the AOT compiler doesn't have threads enabled */
return !mono_opt_wasm_disable_threads;
#endif
#else
return TRUE;
Expand Down Expand Up @@ -2564,11 +2567,11 @@ emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, Mono
MonoExceptionClause *clause;
MonoType *object_type = mono_get_object_type ();
#if defined (TARGET_WASM)
/* in the AOT compiler emit blocking transitions if --wasm-gc-safepoints was used */
/* in the AOT compiler emit blocking transitions if --wasm-disable-threads was used */
#ifndef DISABLE_THREADS
const gboolean do_blocking_transition = TRUE;
#else
const gboolean do_blocking_transition = mono_opt_wasm_gc_safepoints;
const gboolean do_blocking_transition = !mono_opt_wasm_disable_threads;
#endif
#else
const gboolean do_blocking_transition = TRUE;
Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/metadata/marshal-shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "mono/metadata/class-internals.h"
#include "metadata/reflection-internals.h"
#include "mono/metadata/handle.h"
#include <mono/utils/options.h>


#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
Expand Down Expand Up @@ -962,6 +963,10 @@ mono_marshal_shared_emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, g
void
mono_marshal_shared_emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, MonoJitICallId checkpoint_icall_id)
{
if(mono_opt_wasm_disable_threads) {
return;
}

int pos_noabort, pos_noex;

mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
Expand Down
6 changes: 6 additions & 0 deletions src/mono/mono/metadata/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1160,8 +1160,11 @@ mono_monitor_try_enter_loop_if_interrupted (MonoObject *obj, guint32 ms,
res = mono_monitor_try_enter_internal (obj, ms, allow_interruption);
if (res == -1) {
// The wait was interrupted and the monitor was not acquired.
#ifndef DISABLE_THREADS
MonoException *exc;
#endif
HANDLE_FUNCTION_ENTER ();
#ifndef DISABLE_THREADS
exc = mono_thread_interruption_checkpoint ();
if (exc) {
MONO_HANDLE_NEW (MonoException, exc);
Expand All @@ -1170,9 +1173,12 @@ mono_monitor_try_enter_loop_if_interrupted (MonoObject *obj, guint32 ms,
else
mono_set_pending_exception (exc);
}
#endif
HANDLE_FUNCTION_RETURN ();
#ifndef DISABLE_THREADS
if (exc)
return FALSE;
#endif
// The interrupt was a false positive. Ignore it from now on.
// This feels like a hack.
// threads.c should give us less confusing directions.
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/metadata/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,12 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
* throw tie for the type.
*/
if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
#ifndef DISABLE_THREADS
pending_tae = TRUE;
mono_thread_resume_interruption (FALSE);
#else // DISABLE_THREADS
g_assert_not_reached ();
#endif // DISABLE_THREADS
}
} else {
/* this just blocks until the initializing thread is done */
Expand Down
50 changes: 50 additions & 0 deletions src/mono/mono/metadata/threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,24 +282,31 @@ enum {
ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
};

#ifndef DISABLE_THREADS
static int
mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
{
gsize state = thread->thread_state;
return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
}
#endif

gboolean
mono_threads_is_current_thread_in_protected_block (void)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();

return mono_thread_get_abort_prot_block_count (thread) > 0;
#else
return false;
#endif
}

void
mono_threads_begin_abort_protected_block (void)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();
gsize old_state, new_state;
int new_val;
Expand All @@ -323,8 +330,10 @@ mono_threads_begin_abort_protected_block (void)
} else {
THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, mono_thread_interruption_request_flag);
}
#endif
}

#ifndef DISABLE_THREADS
static gboolean
mono_thread_state_has_interruption (gsize state)
{
Expand All @@ -338,10 +347,12 @@ mono_thread_state_has_interruption (gsize state)

return FALSE;
}
#endif

gboolean
mono_threads_end_abort_protected_block (void)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();
gsize old_state, new_state;
int new_val;
Expand All @@ -364,15 +375,20 @@ mono_threads_end_abort_protected_block (void)
}

return mono_thread_state_has_interruption (new_state);
#else
return FALSE;
#endif
}

#ifndef DISABLE_THREADS
static gboolean
mono_thread_get_interruption_requested (MonoInternalThread *thread)
{
gsize state = thread->thread_state;

return mono_thread_state_has_interruption (state);
}
#endif

/*
* Returns TRUE is there was a state change
Expand All @@ -381,6 +397,7 @@ mono_thread_get_interruption_requested (MonoInternalThread *thread)
static gboolean
mono_thread_clear_interruption_requested (MonoInternalThread *thread)
{
#ifndef DISABLE_THREADS
gsize old_state, new_state;
do {
old_state = thread->thread_state;
Expand All @@ -401,23 +418,34 @@ mono_thread_clear_interruption_requested (MonoInternalThread *thread)
if (mono_thread_interruption_request_flag < 0)
g_warning ("bad mono_thread_interruption_request_flag state");
return TRUE;
#else
return FALSE;
#endif
}

static gboolean
mono_thread_clear_interruption_requested_handle (MonoInternalThreadHandle thread)
{
#ifndef DISABLE_THREADS
// Internal threads are pinned so shallow coop/handle.
return mono_thread_clear_interruption_requested (mono_internal_thread_handle_ptr (thread));
#else
return FALSE;
#endif
}

/* Returns TRUE is there was a state change and the interruption can be processed */
static gboolean
mono_thread_set_interruption_requested (MonoInternalThread *thread)
{
#ifndef DISABLE_THREADS
//always force when the current thread is doing it to itself.
gboolean sync = thread == mono_thread_internal_current ();
/* Normally synchronous interruptions can bypass abort protection. */
return mono_thread_set_interruption_requested_flags (thread, sync);
#else
g_assert_not_reached ();
#endif
}

/* Returns TRUE if there was a state change and the interruption can be
Expand All @@ -430,16 +458,21 @@ mono_thread_set_interruption_requested (MonoInternalThread *thread)
static gboolean
mono_thread_set_self_interruption_respect_abort_prot (void)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();
/* N.B. Sets the ASYNC_REQUESTED_BIT for current this thread,
* which is unusual. */
return mono_thread_set_interruption_requested_flags (thread, FALSE);
#else
g_assert_not_reached ();
#endif
}

/* Returns TRUE if there was a state change and the interruption can be processed. */
static gboolean
mono_thread_set_interruption_requested_flags (MonoInternalThread *thread, gboolean sync)
{
#ifndef DISABLE_THREADS
gsize old_state, new_state;
do {
old_state = thread->thread_state;
Expand All @@ -463,6 +496,9 @@ mono_thread_set_interruption_requested_flags (MonoInternalThread *thread, gboole
}

return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
#else
g_assert_not_reached ();
#endif
}

static MonoNativeThreadId
Expand Down Expand Up @@ -3686,6 +3722,7 @@ mono_thread_execute_interruption_ptr (void)
static gboolean
mono_thread_request_interruption_internal (gboolean running_managed, MonoExceptionHandle *pexc)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();

/* The thread may already be stopping */
Expand All @@ -3710,6 +3747,9 @@ mono_thread_request_interruption_internal (gboolean running_managed, MonoExcepti
return FALSE;
}
return mono_thread_execute_interruption (pexc);
#else // DISABLE_THREADS
g_assert_not_reached ();
#endif
}

static void
Expand All @@ -3729,6 +3769,7 @@ mono_thread_request_interruption_managed (MonoExceptionHandle *exc)
void
mono_thread_resume_interruption (gboolean exec)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();
gboolean still_aborting;

Expand All @@ -3751,23 +3792,29 @@ mono_thread_resume_interruption (gboolean exec)

if (exec) // Ignore the exception here, it will be raised later.
mono_thread_execute_interruption_void ();
#else
g_assert_not_reached ();
#endif
}

gboolean
mono_thread_interruption_requested (void)
{
#ifndef DISABLE_THREADS
if (mono_thread_interruption_request_flag) {
MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread != NULL)
return mono_thread_get_interruption_requested (thread);
}
#endif
return FALSE;
}

static MonoException*
mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
{
#ifndef DISABLE_THREADS
MonoInternalThread *thread = mono_thread_internal_current ();

/* The thread may already be stopping */
Expand All @@ -3779,6 +3826,9 @@ mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
return NULL;

return mono_thread_execute_interruption_ptr ();
#else
return NULL;
#endif
}

/*
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,7 @@ interp_throw_ex_general (
THROW_EX (interp_get_exception_null_reference (frame, ip), ip); \
} while (0)

#ifndef DISABLE_THREADS
#define EXCEPTION_CHECKPOINT \
do { \
if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
Expand All @@ -1140,6 +1141,9 @@ interp_throw_ex_general (
THROW_EX_GENERAL (exc, ip, TRUE); \
} \
} while (0)
#else
#define EXCEPTION_CHECKPOINT do { } while (0);
#endif

// Reduce duplicate code in mono_interp_exec_method
static MONO_NEVER_INLINE void
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/mini/mini-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -2422,8 +2422,12 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
}
}
if (is_outside) {
#ifndef DISABLE_THREADS
jit_tls->handler_block = NULL;
mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
#else // DISABLE_THREADS
g_assert_not_reached ();
#endif // DISABLE_THREADS
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/mini.h
Original file line number Diff line number Diff line change
Expand Up @@ -2995,7 +2995,7 @@ mini_safepoints_enabled (void)
#ifndef DISABLE_THREADS
return TRUE;
#else
return mono_opt_wasm_gc_safepoints;
return !mono_opt_wasm_disable_threads;
#endif
#else
return TRUE;
Expand Down
6 changes: 3 additions & 3 deletions src/mono/mono/utils/options-def.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ DEFINE_BOOL(aot_lazy_assembly_load, "aot-lazy-assembly-load", FALSE, "Load assem
DEFINE_BOOL(interp_pgo_recording, "interp-pgo-recording", FALSE, "Record interpreter tiering information for automatic PGO")
#else
DEFINE_BOOL(interp_pgo_recording, "interp-pgo-recording", FALSE, "Record interpreter tiering information for automatic PGO")
DEFINE_BOOL(wasm_gc_safepoints, "wasm-gc-safepoints", FALSE, "Use GC safepoints on WASM")
DEFINE_BOOL(wasm_disable_threads, "wasm-disable-threads", FALSE, "Disable threads on WASM")
#endif
DEFINE_BOOL(interp_pgo_logging, "interp-pgo-logging", FALSE, "Log messages when interpreter PGO optimizes a method or updates its table")
DEFINE_BOOL(interp_codegen_timing, "interp-codegen-timing", FALSE, "Measure time spent generating interpreter code and log it periodically")
Expand All @@ -80,7 +80,7 @@ DEFINE_BOOL(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled"
// jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites
DEFINE_BOOL(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", TRUE, "JIT specialized WASM do_jit_call trampolines")

DEFINE_BOOL(wasm_gc_safepoints, "wasm-gc-safepoints", FALSE, "Use GC safepoints on WASM")
DEFINE_BOOL(wasm_disable_threads, "wasm-disable-threads", TRUE, "Disable threads on WASM")
#else
// traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces
DEFINE_BOOL(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", TRUE, "JIT interpreter opcode traces into WASM")
Expand All @@ -89,7 +89,7 @@ DEFINE_BOOL_READONLY(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry
// jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites
DEFINE_BOOL_READONLY(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", FALSE, "JIT specialized WASM do_jit_call trampolines")

DEFINE_BOOL_READONLY(wasm_gc_safepoints, "wasm-gc-safepoints", TRUE, "Use GC safepoints on WASM")
DEFINE_BOOL(wasm_disable_threads, "wasm-disable-threads", FALSE, "Disable threads on WASM")
#endif // DISABLE_THREADS

// enables using WASM try/catch_all instructions where appropriate (currently only do_jit_call),
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/build/WasmApp.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@
<MonoAOTCompilerDefaultAotArguments Include="mattr=simd" Condition="'$(WasmEnableSIMD)' == 'true'" />
<MonoAOTCompilerDefaultProcessArguments Include="-v" Condition="'$(WasmAOTCompilerVerbose)' == 'true'" />
<MonoAOTCompilerDefaultProcessArguments Include="--wasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" />
<MonoAOTCompilerDefaultProcessArguments Include="--wasm-gc-safepoints" Condition="'$(WasmEnableThreads)' == 'true'" />
<MonoAOTCompilerDefaultProcessArguments Include="--wasm-disable-threads" Condition="'$(WasmEnableThreads)' != 'true' and '$(RuntimeIdentifier)' == 'browser-wasm'" />
<AotProfilePath Include="$(WasmAotProfilePath)"/>
</ItemGroup>
<ItemGroup>
Expand Down
Loading