gboolean mono_thread_info_resume (MonoNativeThreadId tid) { gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */ MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/ if (!info) { result = FALSE; goto cleanup; } result = mono_thread_info_core_resume (info); cleanup: mono_hazard_pointer_clear (hp, 1); return result; }
void mono_runtime_shutdown_stat_profiler (void) { mono_atomic_store_i32 (&sampling_thread_running, 0); mono_profiler_sampling_thread_post (); #ifndef HOST_DARWIN /* * There is a slight problem when we're using CLOCK_PROCESS_CPUTIME_ID: If * we're shutting down and there's largely no activity in the process other * than waiting for the sampler thread to shut down, it can take upwards of * 20 seconds (depending on a lot of factors) for us to shut down because * the sleep progresses very slowly as a result of the low CPU activity. * * We fix this by repeatedly sending the profiler signal to the sampler * thread in order to interrupt the sleep. clock_sleep_ns_abs () will check * sampling_thread_running upon an interrupt and return immediately if it's * zero. profiler_signal_handler () has a special case to ignore the signal * for the sampler thread. */ MonoThreadInfo *info; // Did it shut down already? if ((info = mono_thread_info_lookup (sampling_thread))) { while (!mono_atomic_load_i32 (&sampling_thread_exiting)) { mono_threads_pthread_kill (info, profiler_signal); mono_thread_info_usleep (10 * 1000 /* 10ms */); } // Make sure info can be freed. mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); } #endif mono_os_event_wait_one (&sampling_thread_exited, MONO_INFINITE_WAIT, FALSE); mono_os_event_destroy (&sampling_thread_exited); /* * We can't safely remove the signal handler because we have no guarantee * that all pending signals have been delivered at this point. This should * not really be a problem anyway. */ //remove_signal_handler (profiler_signal); }
/* 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; }
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; 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); 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 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) { MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/ if (!info) return NULL; EnterCriticalSection (&info->suspend_lock); /*thread is on the process of detaching*/ if (mono_thread_info_run_state (info) > STATE_RUNNING) { mono_hazard_pointer_clear (hp, 1); 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); LeaveCriticalSection (&info->suspend_lock); return info; } if (!mono_threads_core_suspend (info)) { LeaveCriticalSection (&info->suspend_lock); mono_hazard_pointer_clear (hp, 1); return NULL; } if (interrupt_kernel) mono_threads_core_interrupt (info); ++info->suspend_count; info->thread_state |= STATE_SUSPENDED; LeaveCriticalSection (&info->suspend_lock); mono_hazard_pointer_clear (hp, 1); return info; }
/* The return value is only valid until a matching mono_thread_info_resume is called */ static MonoThreadInfo* suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel) { MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/ if (!info) return NULL; switch (mono_threads_transition_request_async_suspension (info)) { case AsyncSuspendAlreadySuspended: mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections return info; case AsyncSuspendWait: mono_threads_add_to_pending_operation_set (info); break; case AsyncSuspendInitSuspend: if (!begin_async_suspend (info, interrupt_kernel)) { mono_hazard_pointer_clear (hp, 1); return NULL; } break; case AsyncSuspendBlocking: if (interrupt_kernel) mono_threads_suspend_abort_syscall (info); break; default: g_assert_not_reached (); } //Wait for the pending suspend to finish mono_threads_wait_pending_operations (); if (!check_async_suspend (info)) { mono_thread_info_core_resume (info); mono_threads_wait_pending_operations (); mono_hazard_pointer_clear (hp, 1); return NULL; } return info; }
/* 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; } switch (mono_threads_transition_request_async_suspension (info)) { case AsyncSuspendAlreadySuspended: mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections return info; case AsyncSuspendWait: mono_threads_add_to_pending_operation_set (info); break; case AsyncSuspendInitSuspend: if (!mono_threads_core_begin_async_suspend (info, interrupt_kernel)) { mono_hazard_pointer_clear (hp, 1); *error_condition = "Could not suspend thread"; return NULL; } } //Wait for the pending suspend to finish mono_threads_wait_pending_operations (); if (!mono_threads_core_check_suspend_result (info)) { mono_hazard_pointer_clear (hp, 1); *error_condition = "Post suspend failed"; return NULL; } return info; }