* Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
*/
+#include <config.h>
+
+/* enable pthread extensions */
+#ifdef TARGET_MACH
+#define _DARWIN_C_SOURCE
+#endif
+
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-semaphore.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-threads-coop.h>
#ifdef TARGET_OSX
#include <mono/utils/mach-support.h>
#endif
-#ifdef USE_COOP_BACKEND
+#ifdef _MSC_VER
+// TODO: Find MSVC replacement for __builtin_unwind_init
+#define SAVE_REGS_ON_STACK g_assert_not_reached ();
+#else
+#define SAVE_REGS_ON_STACK __builtin_unwind_init ();
+#endif
volatile size_t mono_polling_required;
-static int coop_reset_blocking_count, coop_try_blocking_count, coop_do_blocking_count, coop_do_polling_count, coop_save_count;
+static int coop_reset_blocking_count;
+static int coop_try_blocking_count;
+static int coop_do_blocking_count;
+static int coop_do_polling_count;
+static int coop_save_count;
void
mono_threads_state_poll (void)
{
MonoThreadInfo *info;
+
+ g_assert (mono_threads_is_coop_enabled ());
+
++coop_do_polling_count;
info = mono_thread_info_current_unchecked ();
}
}
+static void *
+return_stack_ptr ()
+{
+ int i;
+ return &i;
+}
+
+static void
+copy_stack_data (MonoThreadInfo *info, void* stackdata_begin)
+{
+ MonoThreadUnwindState *state;
+ int stackdata_size;
+ void* stackdata_end = return_stack_ptr ();
+
+ SAVE_REGS_ON_STACK;
+
+ state = &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
+
+ stackdata_size = (char*)stackdata_begin - (char*)stackdata_end;
+ if (stackdata_size <= 0)
+ g_error ("stackdata_size = %d, but must be > 0, stackdata_begin = %p, stackdata_end = %p", stackdata_size, stackdata_begin, stackdata_end);
+
+ g_byte_array_set_size (info->stackdata, stackdata_size);
+ state->gc_stackdata = info->stackdata->data;
+ memcpy (state->gc_stackdata, stackdata_end, stackdata_size);
+
+ state->gc_stackdata_size = stackdata_size;
+}
+
void*
-mono_threads_prepare_blocking (void)
+mono_threads_prepare_blocking (void* stackdata)
{
MonoThreadInfo *info;
+
+ if (!mono_threads_is_coop_enabled ())
+ return NULL;
+
++coop_do_blocking_count;
info = mono_thread_info_current_unchecked ();
return NULL;
}
+ copy_stack_data (info, stackdata);
+
retry:
++coop_save_count;
mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
}
void
-mono_threads_finish_blocking (void *cookie)
+mono_threads_finish_blocking (void *cookie, void* stackdata)
{
static gboolean warned_about_bad_transition;
- MonoThreadInfo *info = cookie;
+ MonoThreadInfo *info;
+
+ if (!mono_threads_is_coop_enabled ())
+ return;
+ info = cookie;
if (!info)
return;
void*
-mono_threads_reset_blocking_start (void)
+mono_threads_reset_blocking_start (void* stackdata)
{
- MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+ MonoThreadInfo *info;
+
+ if (!mono_threads_is_coop_enabled ())
+ return NULL;
+
++coop_reset_blocking_count;
+ info = mono_thread_info_current_unchecked ();
/* If the thread is not attached, it doesn't make sense prepare for suspend. */
if (!info || !mono_thread_info_is_live (info))
return NULL;
+ copy_stack_data (info, stackdata);
+
switch (mono_threads_transition_abort_blocking (info)) {
case AbortBlockingIgnore:
info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
}
void
-mono_threads_reset_blocking_end (void *cookie)
+mono_threads_reset_blocking_end (void *cookie, void* stackdata)
{
- MonoThreadInfo *info = cookie;
+ MonoThreadInfo *info;
+ if (!mono_threads_is_coop_enabled ())
+ return;
+
+ info = cookie;
if (!info)
return;
g_assert (info == mono_thread_info_current_unchecked ());
- mono_threads_prepare_blocking ();
+ mono_threads_prepare_blocking (stackdata);
}
void*
-mono_threads_try_prepare_blocking (void)
+mono_threads_try_prepare_blocking (void* stackdata)
{
MonoThreadInfo *info;
+
+ if (!mono_threads_is_coop_enabled ())
+ return NULL;
+
++coop_try_blocking_count;
info = mono_thread_info_current_unchecked ();
return NULL;
}
+ copy_stack_data (info, stackdata);
+
retry:
++coop_save_count;
mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
}
void
-mono_threads_finish_try_blocking (void* cookie)
-{
- mono_threads_finish_blocking (cookie);
-}
-
-gboolean
-mono_threads_core_begin_async_resume (MonoThreadInfo *info)
-{
- g_error ("FIXME");
- return FALSE;
-}
-
-gboolean
-mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
+mono_threads_finish_try_blocking (void* cookie, void* stackdata)
{
- mono_threads_add_to_pending_operation_set (info);
- /* There's nothing else to do after we async request the thread to suspend */
- return TRUE;
-}
+ if (!mono_threads_is_coop_enabled ())
+ return;
-gboolean
-mono_threads_core_check_suspend_result (MonoThreadInfo *info)
-{
- /* Async suspend can't async fail on coop */
- return TRUE;
+ mono_threads_finish_blocking (cookie, stackdata);
}
void
-mono_threads_init_platform (void)
+mono_threads_init_coop (void)
{
+ if (!mono_threads_is_coop_enabled ())
+ return;
+
mono_counters_register ("Coop Reset Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_reset_blocking_count);
mono_counters_register ("Coop Try Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_try_blocking_count);
mono_counters_register ("Coop Do Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_blocking_count);
}
void
-mono_threads_platform_free (MonoThreadInfo *info)
-{
-#ifdef TARGET_OSX
- mach_port_deallocate (current_task (), info->native_handle);
-#endif
-
- //See the above for what's wrong here.
-}
-
-void
-mono_threads_platform_register (MonoThreadInfo *info)
-{
-#ifdef TARGET_OSX
- info->native_handle = mach_thread_self ();
-#endif
-
- //See the above for what's wrong here.
-}
-
-void
-mono_threads_core_begin_global_suspend (void)
+mono_threads_coop_begin_global_suspend (void)
{
- mono_polling_required = 1;
+ if (mono_threads_is_coop_enabled ())
+ mono_polling_required = 1;
}
void
-mono_threads_core_end_global_suspend (void)
+mono_threads_coop_end_global_suspend (void)
{
- mono_polling_required = 0;
+ if (mono_threads_is_coop_enabled ())
+ mono_polling_required = 0;
}
void*
-mono_threads_enter_gc_unsafe_region (void)
+mono_threads_enter_gc_unsafe_region (void* stackdata)
{
- return mono_threads_reset_blocking_start ();
-}
-
-void
-mono_threads_exit_gc_unsafe_region (void *regions_cookie)
-{
- mono_threads_reset_blocking_end (regions_cookie);
-}
-
-#else
+ if (!mono_threads_is_coop_enabled ())
+ return NULL;
-void*
-mono_threads_enter_gc_unsafe_region (void)
-{
- return NULL;
+ return mono_threads_reset_blocking_start (stackdata);
}
void
-mono_threads_exit_gc_unsafe_region (void *regions_cookie)
+mono_threads_exit_gc_unsafe_region (void *regions_cookie, void* stackdata)
{
-}
+ if (!mono_threads_is_coop_enabled ())
+ return;
-#endif
\ No newline at end of file
+ mono_threads_reset_blocking_end (regions_cookie, stackdata);
+}