- /*
- * mono-threads.c: Coop threading
+/**
+ * \file
+ * Coop threading
*
* Author:
* Rodrigo Kumpera (kumpera@gmail.com)
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-threads-api.h>
#include <mono/utils/checked-build.h>
+#include <mono/utils/mono-threads-debug.h>
#ifdef TARGET_OSX
#include <mono/utils/mach-support.h>
stack = mono_native_tls_get_value (coop_reset_count_stack_key);
if (!stack || 0 == stack->len)
- mono_fatal_with_history ("Received cookie %p but found no stack at all, %x\n", received_cookie);
+ mono_fatal_with_history ("Received cookie %p but found no stack at all\n", received_cookie);
expected_cookie = g_array_index (stack, gpointer, stack->len - 1);
stack->len --;
static int coop_do_polling_count;
static int coop_save_count;
+static void
+mono_threads_state_poll_with_info (MonoThreadInfo *info);
+
void
mono_threads_state_poll (void)
{
- MonoThreadInfo *info;
+ mono_threads_state_poll_with_info (mono_thread_info_current_unchecked ());
+}
- g_assert (mono_threads_is_coop_enabled ());
+static void
+mono_threads_state_poll_with_info (MonoThreadInfo *info)
+{
+ g_assert (mono_threads_is_blocking_transition_enabled ());
++coop_do_polling_count;
- info = mono_thread_info_current_unchecked ();
if (!info)
return;
+
THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", mono_thread_info_get_tid (info));
/* Fast check for pending suspend requests */
/* commit the saved state and notify others if needed */
switch (mono_threads_transition_state_poll (info)) {
case SelfSuspendResumed:
- return;
+ break;
case SelfSuspendWait:
mono_thread_info_wait_for_resume (info);
break;
mono_thread_info_wait_for_resume (info);
break;
}
+
+ if (info->async_target) {
+ info->async_target (info->user_data);
+ info->async_target = NULL;
+ info->user_data = NULL;
+ }
}
-static void *
-return_stack_ptr ()
+static volatile gpointer* dummy_global;
+
+static MONO_NEVER_INLINE
+void*
+return_stack_ptr (gpointer *i)
{
- gpointer i;
- return &i;
+ dummy_global = i;
+ return i;
}
static void
{
MonoThreadUnwindState *state;
int stackdata_size;
- void* stackdata_end = return_stack_ptr ();
+ gpointer dummy;
+ void* stackdata_end = return_stack_ptr (&dummy);
SAVE_REGS_ON_STACK;
{
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;
case DoBlockingContinue:
break;
case DoBlockingPollAndRetry:
- mono_threads_state_poll ();
+ mono_threads_state_poll_with_info (info);
goto retry;
}
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;
default:
g_error ("Unknown thread state");
}
+
+ if (info->async_target) {
+ info->async_target (info->user_data);
+ info->async_target = NULL;
+ info->user_data = NULL;
+ }
}
void
{
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;
info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
return NULL;
case AbortBlockingIgnoreAndPoll:
- mono_threads_state_poll ();
+ mono_threads_state_poll_with_info (info);
return NULL;
case AbortBlockingOk:
info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
g_error ("Unknown thread state");
}
+ if (info->async_target) {
+ info->async_target (info->user_data);
+ info->async_target = NULL;
+ info->user_data = NULL;
+ }
+
return info;
}
gpointer
-mono_threads_enter_gc_unsafe_region_cookie (MonoThreadInfo *info)
+mono_threads_enter_gc_unsafe_region_cookie (void)
{
- g_assert (mono_threads_is_coop_enabled ());
+ MonoThreadInfo *info;
+
+ g_assert (mono_threads_is_blocking_transition_enabled ());
+
+ info = mono_thread_info_current_unchecked ();
+
+ check_info (info, "enter (cookie)", "unsafe");
#ifdef ENABLE_CHECKED_BUILD_GC
if (mono_check_mode_enabled (MONO_CHECK_MODE_GC))
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)
return;
-#ifdef ENABLE_CHECKED_BUILD_GC
- if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
-#endif
- {
- g_assert (((MonoThreadInfo *)cookie) == mono_thread_info_current_unchecked ());
- }
-
mono_threads_enter_gc_safe_region_unbalanced (stackdata);
}
#else
static int is_coop_enabled = -1;
if (G_UNLIKELY (is_coop_enabled == -1))
- is_coop_enabled = g_getenv ("MONO_ENABLE_COOP") != NULL ? 1 : 0;
+ is_coop_enabled = g_hasenv ("MONO_ENABLE_COOP") ? 1 : 0;
return is_coop_enabled == 1;
#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_init_coop (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);