<opcode name="mono_ldptr_nursery_start" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x16" flow="next" />
<opcode name="mono_ldptr_nursery_bits" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x17" flow="next" />
<opcode name="mono_calli_extra_arg" input="VarPop" output="VarPush" args="InlineSig" o1="0xF0" o2="0x18" flow="call" />
+<opcode name="mono_lddomain" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x19" flow="next" />
</opdesc>
OPDEF(CEE_MONO_LDPTR_NURSERY_START, "mono_ldptr_nursery_start", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x16, NEXT)
OPDEF(CEE_MONO_LDPTR_NURSERY_BITS, "mono_ldptr_nursery_bits", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x17, NEXT)
OPDEF(CEE_MONO_CALLI_EXTRA_ARG, "mono_calli_extra_arg", VarPop, VarPush, InlineSig, X, 2, 0xF0, 0x18, CALL)
+OPDEF(CEE_MONO_LDDOMAIN, "mono_lddomain", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x19, NEXT)
#ifndef OPALIAS
#define _MONO_CIL_OPALIAS_DEFINED_
#define OPALIAS(a,s,r)
register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
register_icall (mono_threads_enter_gc_safe_region_unbalanced, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE);
register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
+ register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
+ register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
mono_cominterop_init ();
mono_remoting_init ();
#else
MonoMethodSignature *sig, *csig;
MonoExceptionClause *clauses, *clause_finally, *clause_catch;
- int i, *tmp_locals, ex_local, e_local;
+ int i, *tmp_locals, ex_local, e_local, attach_cookie_local, attach_dummy_local;
int leave_try_pos, leave_catch_pos, ex_m1_pos;
gboolean closed = FALSE;
ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
+ attach_cookie_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ attach_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
/*
* guint32 ex = -1;
* try {
- * mono_jit_attach ();
+ * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
+ * mono_threads_attach_coop ();
*
* <interrupt check>
*
* } catch (Exception e) {
* ex = mono_gchandle_new (e, false);
* } finally {
- * mono_jit_detach ();
+ * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
+ * mono_threads_detach_coop ();
*
* if (ex != -1)
* mono_marshal_ftnptr_eh_callback (ex);
/* try { */
clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
- /*
- * Might need to attach the thread to the JIT or change the
- * domain for the callback.
- *
- * Also does the (STARTING|BLOCKING|RUNNING) -> RUNNING thread state transtion
- *
- * mono_jit_attach ();
- */
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
+ if (!mono_threads_is_coop_enabled ()) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
+ } else {
+ /* mono_threads_attach_coop (); */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
+ mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+ mono_mb_emit_icall (mb, mono_threads_attach_coop);
+ mono_mb_emit_stloc (mb, attach_cookie_local);
+ }
/* <interrupt check> */
emit_thread_interrupt_checkpoint (mb);
clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
clause_finally->handler_offset = mono_mb_get_label (mb);
- /*
- * Also does the RUNNING -> (BLOCKING|RUNNING) thread state transition
- *
- * mono_jit_detach ();
- */
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
+ if (!mono_threads_is_coop_enabled ()) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
+ } else {
+ /* mono_threads_detach_coop (); */
+ mono_mb_emit_ldloc (mb, attach_cookie_local);
+ mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+ mono_mb_emit_icall (mb, mono_threads_detach_coop);
+ }
/* if (ex != -1) */
mono_mb_emit_ldloc (mb, ex_local);
sgen_thread_detach (SgenThreadInfo *p)
{
/* If a delegate is passed to native code and invoked on a thread we dont
- * know about, the jit will register it with mono_jit_thread_attach, but
+ * know about, marshal will register it with mono_threads_attach_coop, but
* we have no way of knowing when that thread goes away. SGen has a TSD
* so we assume that if the domain is still registered, we can detach
* the thread
void ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces);
+MONO_API gpointer
+mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy);
+
+MONO_API void
+mono_threads_detach_coop (gpointer cookie, gpointer *dummy);
+
#endif /* _MONO_METADATA_THREADS_TYPES_H_ */
#include <mono/utils/mono-tls.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-memory-model.h>
+#include <mono/utils/mono-threads-coop.h>
+#include <mono/utils/mono-error-internals.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/reflection-internals.h>
{
mono_threads_get_thread_dump (out_threads, out_stack_traces);
}
+
+/*
+ * mono_threads_attach_coop: called by native->managed wrappers
+ *
+ * In non-coop mode:
+ * - @dummy: is NULL
+ * - @return: the original domain which needs to be restored, or NULL.
+ *
+ * In coop mode:
+ * - @dummy: contains the original domain
+ * - @return: a cookie containing current MonoThreadInfo*.
+ */
+gpointer
+mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
+{
+ MonoError error;
+ MonoDomain *orig;
+ gboolean fresh_thread;
+
+ if (!domain) {
+ /* Happens when called from AOTed code which is only used in the root domain. */
+ domain = mono_get_root_domain ();
+ }
+
+ g_assert (domain);
+
+ /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
+ * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
+ * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
+ * we're only responsible for making the cookie. */
+ if (mono_threads_is_coop_enabled ()) {
+ MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+ fresh_thread = !info || !mono_thread_info_is_live (info);
+ }
+
+ if (!mono_thread_internal_current ()) {
+ mono_thread_attach_full (domain, FALSE, &error);
+ mono_error_assert_ok (&error);
+
+ // #678164
+ mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
+ }
+
+ orig = mono_domain_get ();
+ if (orig != domain)
+ mono_domain_set (domain, TRUE);
+
+ if (!mono_threads_is_coop_enabled ())
+ return orig != domain ? orig : NULL;
+
+ if (fresh_thread) {
+ *dummy = NULL;
+ /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
+ * return the right cookie. */
+ return mono_threads_enter_gc_unsafe_region_cookie (mono_thread_info_current ());
+ } else {
+ *dummy = orig;
+ /* thread state (BLOCKING|RUNNING) -> RUNNING */
+ return mono_threads_enter_gc_unsafe_region (dummy);
+ }
+}
+
+/*
+ * mono_threads_detach_coop: called by native->managed wrappers
+ *
+ * In non-coop mode:
+ * - @cookie: the original domain which needs to be restored, or NULL.
+ * - @dummy: is NULL
+ *
+ * In coop mode:
+ * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
+ * - @dummy: contains the original domain
+ */
+void
+mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
+{
+ MonoDomain *domain, *orig;
+
+ if (!mono_threads_is_coop_enabled ()) {
+ orig = (MonoDomain*) cookie;
+ if (orig)
+ mono_domain_set (orig, TRUE);
+ } else {
+ orig = (MonoDomain*) *dummy;
+
+ domain = mono_domain_get ();
+ g_assert (domain);
+
+ /* it won't do anything if cookie is NULL
+ * thread state RUNNING -> (RUNNING|BLOCKING) */
+ mono_threads_exit_gc_unsafe_region (cookie, dummy);
+
+ if (orig != domain) {
+ if (!orig)
+ mono_domain_unset ();
+ else
+ mono_domain_set (orig, TRUE);
+ }
+ }
+}
ErrorCode err;
gboolean no_reply;
gboolean attach_failed = FALSE;
- gpointer attach_cookie, attach_dummy;
DEBUG_PRINTF (1, "[dbg] Agent thread started, pid=%p\n", (gpointer) (gsize) mono_native_thread_id_get ());
debugger_thread_id = mono_native_thread_id_get ();
- attach_cookie = mono_jit_thread_attach (mono_get_root_domain (), &attach_dummy);
- MonoInternalThread *thread = mono_thread_internal_current ();
- mono_thread_set_name_internal (thread, mono_string_new (mono_get_root_domain (), "Debugger agent"), TRUE, &error);
+ MonoThread *thread = mono_thread_attach (mono_get_root_domain ());
+ mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Debugger agent"), TRUE, &error);
mono_error_assert_ok (&error);
- thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
+ thread->internal_thread->state |= ThreadState_Background;
+ thread->internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
mono_set_is_debugger_attached (TRUE);
start_debugger_thread ();
}
- mono_jit_thread_detach (attach_cookie, &attach_dummy);
-
return 0;
}
MonoInst *ad_ins, *jit_tls_ins;
MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
+ g_assert (!mono_threads_is_coop_enabled ());
+
cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- if (mono_threads_is_coop_enabled ()) {
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
- EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
- ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
- } else {
- EMIT_NEW_PCONST (cfg, ins, NULL);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
+ EMIT_NEW_PCONST (cfg, ins, NULL);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
- ad_ins = mono_get_domain_intrinsic (cfg);
- jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
+ ad_ins = mono_get_domain_intrinsic (cfg);
+ jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
- if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
- NEW_BBLOCK (cfg, next_bb);
- NEW_BBLOCK (cfg, call_bb);
+ if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
+ NEW_BBLOCK (cfg, next_bb);
+ NEW_BBLOCK (cfg, call_bb);
- if (cfg->compile_aot) {
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, domain_ins, NULL);
- } else {
- EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
- }
- MONO_ADD_INS (cfg->cbb, ad_ins);
- MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
- MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
-
- MONO_ADD_INS (cfg->cbb, jit_tls_ins);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
- MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
-
- MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
- MONO_START_BB (cfg, call_bb);
+ if (cfg->compile_aot) {
+ /* AOT code is only used in the root domain */
+ EMIT_NEW_PCONST (cfg, domain_ins, NULL);
+ } else {
+ EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
}
+ MONO_ADD_INS (cfg->cbb, ad_ins);
+ MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
- EMIT_NEW_PCONST (cfg, args [1], NULL);
- ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
+ MONO_ADD_INS (cfg->cbb, jit_tls_ins);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
- if (next_bb)
- MONO_START_BB (cfg, next_bb);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
+ MONO_START_BB (cfg, call_bb);
}
+ /* AOT code is only used in the root domain */
+ EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
+ EMIT_NEW_PCONST (cfg, args [1], NULL);
+ ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
+
+ if (next_bb)
+ MONO_START_BB (cfg, next_bb);
+
ip += 2;
break;
}
constrained_class = NULL;
break;
}
+ case CEE_MONO_LDDOMAIN:
+ CHECK_STACK_OVF (1);
+ EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
+ ip += 2;
+ *sp++ = ins;
+ break;
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;
/*
* mono_jit_thread_attach: called by native->managed wrappers
*
- * In non-coop mode:
- * - @dummy: is NULL
- * - @return: the original domain which needs to be restored, or NULL.
- *
- * In coop mode:
- * - @dummy: contains the original domain
- * - @return: a cookie containing current MonoThreadInfo*.
+ * @dummy: is NULL
+ * @return: the original domain which needs to be restored, or NULL.
*/
gpointer
mono_jit_thread_attach (MonoDomain *domain, gpointer *dummy)
{
MonoDomain *orig;
+ gboolean attached;
+
+ g_assert (!mono_threads_is_coop_enabled ());
if (!domain) {
/* Happens when called from AOTed code which is only used in the root domain. */
g_assert (domain);
- /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING. If we try to
- * reattach we do a BLOCKING->RUNNING transition. If the thread is fresh,
- * mono_thread_attach() will do a STARTING->RUNNING transition so we're only responsible
- * for making the cookie. */
- gboolean fresh_thread = FALSE;
- {
- MonoThreadInfo *info;
-
- info = mono_thread_info_current_unchecked ();
- fresh_thread = !info || !mono_thread_info_is_live (info);
- }
- {
- gboolean attached;
-
#ifdef MONO_HAVE_FAST_TLS
- attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
+ attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
#else
- attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
+ attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
#endif
- if (!attached) {
- mono_thread_attach (domain);
+ if (!attached) {
+ mono_thread_attach (domain);
- // #678164
- mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
- }
+ // #678164
+ mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
+ }
- orig = mono_domain_get ();
- if (orig != domain)
- mono_domain_set (domain, TRUE);
+ orig = mono_domain_get ();
+ if (orig != domain)
+ mono_domain_set (domain, TRUE);
- }
- if (!mono_threads_is_coop_enabled ()) {
- return orig != domain ? orig : NULL;
- } else {
- if (fresh_thread) {
- *dummy = NULL;
- /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
- * return the right cookie. */
- return mono_threads_enter_gc_unsafe_region_cookie (mono_thread_info_current ());
- } else {
- *dummy = orig;
- /* thread state (BLOCKING|RUNNING) -> RUNNING */
- return mono_threads_enter_gc_unsafe_region (dummy);
- }
- }
+ return orig != domain ? orig : NULL;
}
/*
* mono_jit_thread_detach: called by native->managed wrappers
*
- * In non-coop mode:
- * - @cookie: the original domain which needs to be restored, or NULL.
- * - @dummy: is NULL
- *
- * In coop mode:
- * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
- * - @dummy: contains the original domain
+ * @cookie: the original domain which needs to be restored, or NULL.
+ * @dummy: is NULL
*/
void
mono_jit_thread_detach (gpointer cookie, gpointer *dummy)
{
- MonoDomain *domain, *orig;
-
- if (!mono_threads_is_coop_enabled ()) {
- orig = (MonoDomain*) cookie;
-
- if (orig)
- mono_domain_set (orig, TRUE);
- } else {
- orig = (MonoDomain*) *dummy;
-
- domain = mono_domain_get ();
- g_assert (domain);
+ MonoDomain *orig;
- /* it won't do anything if cookie is NULL
- * thread state RUNNING -> (RUNNING|BLOCKING) */
- mono_threads_exit_gc_unsafe_region (cookie, dummy);
+ g_assert (!mono_threads_is_coop_enabled ());
- if (orig != domain) {
- if (!orig)
- mono_domain_unset ();
- else
- mono_domain_set (orig, TRUE);
- }
- }
+ orig = (MonoDomain*) cookie;
+ if (orig)
+ mono_domain_set (orig, TRUE);
}
/**