void mono_thread_info_self_suspend (void) { gboolean ret; MonoThreadInfo *info = mono_thread_info_current (); if (!info) return; MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore); THREADS_DEBUG ("self suspend IN COUNT %d\n", info->suspend_count); g_assert (info->suspend_count == 0); ++info->suspend_count; info->thread_state |= STATE_SELF_SUSPENDED; ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL); g_assert (ret); MONO_SEM_POST (&info->suspend_semaphore); MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore); g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */ MONO_SEM_POST (&info->finish_resume_semaphore); }
gboolean mono_thread_info_resume (MonoNativeThreadId tid) { gboolean result = TRUE; MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/ if (!info) return FALSE; MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore); THREADS_DEBUG ("resume %x IN COUNT %d\n",tid, info->suspend_count); if (info->suspend_count <= 0) { MONO_SEM_POST (&info->suspend_semaphore); mono_hazard_pointer_clear (hp, 1); return FALSE; } /* * The theory here is that if we manage to suspend the thread it means it did not * start cleanup since it take the same lock. */ g_assert (mono_thread_info_get_tid (info)); if (--info->suspend_count == 0) result = mono_thread_info_resume_internal (info); MONO_SEM_POST (&info->suspend_semaphore); mono_hazard_pointer_clear (hp, 1); mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE); return result; }
/* The suspend lock is held during any suspend in progress. A GC that has safepoints must take this lock as part of its STW to make sure no unsafe pending suspend is in progress. */ void mono_thread_info_suspend_lock (void) { MONO_TRY_BLOCKING; MONO_SEM_WAIT_UNITERRUPTIBLE (&global_suspend_semaphore); MONO_FINISH_TRY_BLOCKING; }
static gboolean mono_thread_info_core_resume (MonoThreadInfo *info) { gboolean result; MonoNativeThreadId tid = mono_thread_info_get_tid (info); if (info->create_suspended) { /* Have to special case this, as the normal suspend/resume pair are racy, they don't work if he resume is received before the suspend */ info->create_suspended = FALSE; mono_threads_core_resume_created (info, tid); return TRUE; } MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore); THREADS_DEBUG ("resume %x IN COUNT %d\n", tid, info->suspend_count); if (info->suspend_count <= 0) { MONO_SEM_POST (&info->suspend_semaphore); return FALSE; } /* * The theory here is that if we manage to suspend the thread it means it did not * start cleanup since it take the same lock. */ g_assert (mono_thread_info_get_tid (info)); if (--info->suspend_count == 0) { if (mono_thread_info_suspend_state (info) == STATE_SELF_SUSPENDED) { MONO_SEM_POST (&info->resume_semaphore); MONO_SEM_WAIT_UNITERRUPTIBLE (&info->finish_resume_semaphore); result = TRUE; } else { result = mono_threads_core_resume (info); } info->thread_state &= ~SUSPEND_STATE_MASK; } else { result = TRUE; } MONO_SEM_POST (&info->suspend_semaphore); return result; }
static gboolean mono_thread_info_resume_internal (MonoThreadInfo *info) { gboolean result; if (mono_thread_info_suspend_state (info) == STATE_SELF_SUSPENDED) { MONO_SEM_POST (&info->resume_semaphore); MONO_SEM_WAIT_UNITERRUPTIBLE (&info->finish_resume_semaphore); result = TRUE; } else { result = mono_threads_core_resume (info); } info->thread_state &= ~SUSPEND_STATE_MASK; return result; }
/* The return value is only valid until a matching mono_thread_info_resume is called */ static MonoThreadInfo* mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel, const char **error_condition) { MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/ if (!info) { *error_condition = "Thread not found"; return NULL; } MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore); /*thread is on the process of detaching*/ if (mono_thread_info_run_state (info) > STATE_RUNNING) { mono_hazard_pointer_clear (hp, 1); *error_condition = "Thread is detaching"; return NULL; } THREADS_DEBUG ("suspend %x IN COUNT %d\n", tid, info->suspend_count); if (info->suspend_count) { ++info->suspend_count; mono_hazard_pointer_clear (hp, 1); MONO_SEM_POST (&info->suspend_semaphore); return info; } if (!mono_threads_core_suspend (info)) { MONO_SEM_POST (&info->suspend_semaphore); mono_hazard_pointer_clear (hp, 1); *error_condition = "Could not suspend thread"; return NULL; } if (interrupt_kernel) mono_threads_core_interrupt (info); ++info->suspend_count; info->thread_state |= STATE_SUSPENDED; MONO_SEM_POST (&info->suspend_semaphore); return info; }
/* The suspend lock is held during any suspend in progress. A GC that has safepoints must take this lock as part of its STW to make sure no unsafe pending suspend is in progress. */ void mono_thread_info_suspend_lock (void) { MONO_SEM_WAIT_UNITERRUPTIBLE (&global_suspend_semaphore); }
void mono_thread_info_wait_for_resume (MonoThreadInfo* info) { THREADS_SUSPEND_DEBUG ("**WAIT self-resume %p\n", mono_thread_info_get_tid (info)); MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore); }