mono_mb_add_local (mb, sig->ret);
}
- if (mono_threads_is_coop_enabled ()) {
+ if (mono_threads_is_blocking_transition_enabled ()) {
/* local 4, dummy local used to get a stack address for suspend funcs */
coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
/* local 5, the local to be used when calling the suspend funcs */
}
// In coop mode need to register blocking state during native call
- if (mono_threads_is_coop_enabled ()) {
+ if (mono_threads_is_blocking_transition_enabled ()) {
// Perform an extra, early lookup of the function address, so any exceptions
// potentially resulting from the lookup occur before entering blocking mode.
if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
}
/* Unblock before converting the result, since that can involve calls into the runtime */
- if (mono_threads_is_coop_enabled ()) {
+ if (mono_threads_is_blocking_transition_enabled ()) {
mono_mb_emit_ldloc (mb, coop_gc_var);
mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
mono_mb_emit_icall (mb, mono_threads_exit_gc_safe_region_unbalanced);
/* try { */
clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
- if (!mono_threads_is_coop_enabled ()) {
+ if (!mono_threads_is_blocking_transition_enabled ()) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
} else {
clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
clause_finally->handler_offset = mono_mb_get_label (mb);
- if (!mono_threads_is_coop_enabled ()) {
+ if (!mono_threads_is_blocking_transition_enabled ()) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
} else {
/*
* mono_threads_attach_coop: called by native->managed wrappers
*
- * In non-coop mode:
- * - @dummy: is NULL
+ * - @dummy:
+ * - blocking mode: contains gc unsafe transition cookie
+ * - non-blocking mode: contains random data
* - @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)
{
MonoDomain *orig;
- gboolean fresh_thread = FALSE;
+ MonoThreadInfo *info;
+ gboolean external;
+
+ orig = mono_domain_get ();
if (!domain) {
/* Happens when called from AOTed code which is only used in the root domain. */
domain = mono_get_root_domain ();
+ g_assert (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_threads_is_blocking_transition_enabled ())
+ external = !(info = mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info);
if (!mono_thread_internal_current ()) {
mono_thread_attach_full (domain, FALSE);
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 ();
- } else {
- *dummy = orig;
- /* thread state (BLOCKING|RUNNING) -> RUNNING */
- return mono_threads_enter_gc_unsafe_region (dummy);
+ if (mono_threads_is_blocking_transition_enabled ()) {
+ if (external) {
+ /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
+ * return the right cookie. */
+ *dummy = mono_threads_enter_gc_unsafe_region_cookie ();
+ } else {
+ /* thread state (BLOCKING|RUNNING) -> RUNNING */
+ *dummy = mono_threads_enter_gc_unsafe_region (dummy);
+ }
}
+
+ return orig;
}
/*
* 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
+ * - @dummy:
+ * - blocking mode: contains gc unsafe transition cookie
+ * - non-blocking mode: contains random data
*/
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;
+ orig = (MonoDomain*) cookie;
- domain = mono_domain_get ();
- g_assert (domain);
+ domain = mono_domain_get ();
+ g_assert (domain);
+ if (mono_threads_is_blocking_transition_enabled ()) {
/* it won't do anything if cookie is NULL
* thread state RUNNING -> (RUNNING|BLOCKING) */
- mono_threads_exit_gc_unsafe_region (cookie, dummy);
+ mono_threads_exit_gc_unsafe_region (*dummy, dummy);
+ }
- if (orig != domain) {
- if (!orig)
- mono_domain_unset ();
- else
- mono_domain_set (orig, TRUE);
- }
+ if (orig != domain) {
+ if (!orig)
+ mono_domain_unset ();
+ else
+ mono_domain_set (orig, TRUE);
}
}
++ip;
mono_jit_set_domain (context->original_domain);
MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_MONO_LDDOMAIN)
+ sp->data.p = mono_domain_get ();
+ ++sp;
+ ++ip;
+ MINT_IN_BREAK;
MINT_IN_CASE(MINT_SDB_INTR_LOC)
if (G_UNLIKELY (ss_enabled)) {
static void (*ss_tramp) (void);
OPDEF(MINT_MONO_MEMORY_BARRIER, "mono_memory_barrier", 1, MintOpNoArgs)
OPDEF(MINT_MONO_JIT_ATTACH, "mono_jit_attach", 1, MintOpNoArgs)
OPDEF(MINT_MONO_JIT_DETACH, "mono_jit_detach", 1, MintOpNoArgs)
+OPDEF(MINT_MONO_LDDOMAIN, "mono_lddomain", 1, MintOpNoArgs)
// FIXME: MintOp
OPDEF(MINT_JIT_CALL, "mono_jit_call", 2, MintOpNoArgs)
ADD_CODE (&td, MINT_MONO_JIT_DETACH);
++td.ip;
break;
+ case CEE_MONO_LDDOMAIN:
+ ADD_CODE (&td, MINT_MONO_LDDOMAIN);
+ td.sp [0].type = STACK_TYPE_I;
+ ++td.sp;
+ ++td.ip;
+ break;
default:
g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td.ip, td.ip-header->code);
}
MonoInst *ad_ins, *jit_tls_ins;
MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
- g_assert (!mono_threads_is_coop_enabled ());
+ g_assert (!mono_threads_is_blocking_transition_enabled ());
cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
MonoDomain *orig;
gboolean attached;
- g_assert (!mono_threads_is_coop_enabled ());
+ g_assert (!mono_threads_is_blocking_transition_enabled ());
if (!domain) {
/* Happens when called from AOTed code which is only used in the root domain. */
void
mono_jit_set_domain (MonoDomain *domain)
{
- g_assert (!mono_threads_is_coop_enabled ());
+ g_assert (!mono_threads_is_blocking_transition_enabled ());
if (domain)
mono_domain_set (domain, TRUE);
static void
mono_threads_state_poll_with_info (MonoThreadInfo *info)
{
- g_assert (mono_threads_is_coop_enabled ());
+ g_assert (mono_threads_is_blocking_transition_enabled ());
++coop_do_polling_count;
{
gpointer cookie;
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return NULL;
cookie = mono_threads_enter_gc_safe_region_unbalanced_with_info (info, stackdata);
static gpointer
mono_threads_enter_gc_safe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata)
{
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return NULL;
++coop_do_blocking_count;
void
mono_threads_exit_gc_safe_region (gpointer cookie, gpointer *stackdata)
{
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return;
#ifdef ENABLE_CHECKED_BUILD_GC
{
MonoThreadInfo *info;
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return;
info = (MonoThreadInfo *)cookie;
{
gpointer cookie;
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return NULL;
cookie = mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, stackdata);
gpointer
mono_threads_enter_gc_unsafe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata)
{
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return NULL;
++coop_reset_blocking_count;
{
MonoThreadInfo *info;
- g_assert (mono_threads_is_coop_enabled ());
+ g_assert (mono_threads_is_blocking_transition_enabled ());
info = mono_thread_info_current_unchecked ();
void
mono_threads_exit_gc_unsafe_region (gpointer cookie, gpointer *stackdata)
{
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return;
#ifdef ENABLE_CHECKED_BUILD_GC
void
mono_threads_exit_gc_unsafe_region_unbalanced (gpointer cookie, gpointer *stackdata)
{
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_blocking_transition_enabled ())
return;
if (!cookie)
#endif
}
+gboolean
+mono_threads_is_blocking_transition_enabled (void)
+{
+#if defined(USE_COOP_GC)
+ return TRUE;
+#else
+ static int is_blocking_transition_enabled = -1;
+ if (G_UNLIKELY (is_blocking_transition_enabled == -1))
+ is_blocking_transition_enabled = (g_hasenv ("MONO_ENABLE_COOP") || g_hasenv ("MONO_ENABLE_BLOCKING_TRANSITION")) ? 1 : 0;
+ return is_blocking_transition_enabled == 1;
+#endif
+}
+
void
mono_threads_coop_init (void)
{
- if (!mono_threads_is_coop_enabled ())
+ if (!mono_threads_is_coop_enabled () && !mono_threads_is_blocking_transition_enabled ())
return;
mono_counters_register ("Coop Reset Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_reset_blocking_count);
gboolean
mono_threads_is_coop_enabled (void);
+gboolean
+mono_threads_is_blocking_transition_enabled (void);
+
/* Internal API */
void
if (interrupt_kernel)
mono_threads_suspend_abort_syscall (info);
- break;
+ return info;
default:
g_assert_not_reached ();
}
static void
mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
{
- if (mono_threads_is_coop_enabled ()) {
- g_assert (info);
- g_assert (mono_thread_info_is_current (info));
- g_assert (mono_thread_info_is_live (info));
+ g_assert (info);
+ g_assert (mono_thread_info_is_current (info));
+ g_assert (mono_thread_info_is_live (info));
- MONO_ENTER_GC_SAFE_WITH_INFO(info);
+ MONO_ENTER_GC_SAFE_WITH_INFO(info);
- int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
- g_assert (res != -1);
+ int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
+ g_assert (res != -1);
- MONO_EXIT_GC_SAFE_WITH_INFO;
- } else {
- int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
- g_assert (res != -1);
- }
+ MONO_EXIT_GC_SAFE_WITH_INFO;
}
void
mono_thread_info_suspend_lock (void)
{
- mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
+ MonoThreadInfo *info;
+ gint res;
+
+ info = mono_thread_info_current_unchecked ();
+ if (info && mono_thread_info_is_live (info)) {
+ mono_thread_info_suspend_lock_with_info (info);
+ return;
+ }
+
+ /* mono_thread_info_suspend_lock () can be called from boehm-gc.c on_gc_notification before the new thread's
+ * start_wrapper calls mono_thread_info_attach but after pthread_create calls the start wrapper. */
+
+ res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
+ g_assert (res != -1);
}
void