/* WARNING: If we are trying to suspend a target that is on a critical region and running a syscall we risk looping forever if @interrupt_kernel is FALSE. So, be VERY carefull in calling this with @interrupt_kernel == FALSE. Info is not put on a hazard pointer as a suspended thread cannot exit and be freed. This function MUST be matched with mono_thread_info_finish_suspend or mono_thread_info_finish_suspend_and_resume */ MonoThreadInfo* mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel) { MonoThreadInfo *info = NULL; int sleep_duration = 0; /*FIXME: unify this with self-suspend*/ g_assert (id != mono_native_thread_id_get ()); mono_thread_info_suspend_lock (); for (;;) { const char *suspend_error = "Unknown error"; if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) { g_warning ("failed to suspend thread %p due to %s, hopefully it is dead", (gpointer)id, suspend_error); mono_thread_info_suspend_unlock (); return NULL; } /*WARNING: We now are in interrupt context until we resume the thread. */ if (!is_thread_in_critical_region (info)) break; if (!mono_thread_info_core_resume (info)) { g_warning ("failed to resume thread %p, hopefully it is dead", (gpointer)id); mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); mono_thread_info_suspend_unlock (); return NULL; } THREADS_DEBUG ("restarted thread %p\n", (gpointer)id); if (!sleep_duration) { #ifdef HOST_WIN32 SwitchToThread (); #else sched_yield (); #endif } else { g_usleep (sleep_duration); } sleep_duration += 10; } /* XXX this clears HP 1, so we restated it again */ mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE); mono_thread_info_suspend_unlock (); return info; }
/* WARNING: If we are trying to suspend a target that is on a critical region and running a syscall we risk looping forever if @interrupt_kernel is FALSE. So, be VERY carefull in calling this with @interrupt_kernel == FALSE. */ MonoThreadInfo* mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel) { MonoThreadInfo *info = NULL; int sleep_duration = 0; /*FIXME: unify this with self-suspend*/ g_assert (id != mono_native_thread_id_get ()); mono_thread_info_suspend_lock (); for (;;) { if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel))) { g_warning ("failed to suspend thread %p, hopefully it is dead", (gpointer)id); mono_thread_info_suspend_unlock (); return NULL; } /*WARNING: We now are in interrupt context until we resume the thread. */ if (!is_thread_in_critical_region (info)) break; if (!mono_thread_info_resume (id)) { g_warning ("failed to result thread %p, hopefully it is dead", (gpointer)id); mono_thread_info_suspend_unlock (); return NULL; } THREADS_DEBUG ("restarted thread %p\n", (gpointer)id); if (!sleep_duration) { #ifdef HOST_WIN32 SwitchToThread (); #else sched_yield (); #endif } else { g_usleep (sleep_duration); } sleep_duration += 10; } mono_thread_info_suspend_unlock (); return info; }
static MonoThreadInfo* suspend_sync_nolock (MonoNativeThreadId id, gboolean interrupt_kernel) { MonoThreadInfo *info = NULL; int sleep_duration = 0; for (;;) { const char *suspend_error = "Unknown error"; if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) { mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); return NULL; } /*WARNING: We now are in interrupt context until we resume the thread. */ if (!is_thread_in_critical_region (info)) break; if (!mono_thread_info_core_resume (info)) { mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); return NULL; } THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id); /* Wait for the pending resume to finish */ mono_threads_wait_pending_operations (); if (!sleep_duration) { #ifdef HOST_WIN32 SwitchToThread (); #else sched_yield (); #endif } else { g_usleep (sleep_duration); } sleep_duration += 10; } return info; }