gboolean mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { mono_threads_add_to_pending_operation_set (info); /* There's nothing else to do after we async request the thread to suspend */ return TRUE; }
gboolean mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { kern_return_t ret; gboolean res; g_assert (info); ret = thread_suspend (info->native_handle); THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)info->native_handle, ret); if (ret != KERN_SUCCESS) return FALSE; /* We're in the middle of a self-suspend, resume and register */ if (!mono_threads_transition_finish_async_suspend (info)) { mono_threads_add_to_pending_operation_set (info); g_assert (thread_resume (info->native_handle) == KERN_SUCCESS); THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)info->native_handle, 0); //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall return TRUE; } res = mono_threads_get_runtime_callbacks ()-> thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info); THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)info->native_handle, res); if (res) { if (interrupt_kernel) thread_abort (info->native_handle); } else { mono_threads_transition_async_suspend_compensation (info); g_assert (thread_resume (info->native_handle) == KERN_SUCCESS); THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0); } return res; }
/* 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; } } //Wait for the pending suspend to finish mono_threads_wait_pending_operations (); if (!check_async_suspend (info)) { mono_hazard_pointer_clear (hp, 1); return NULL; } return info; }
void mono_threads_suspend_abort_syscall (MonoThreadInfo *info) { /* We signal a thread to break it from the current syscall. * This signal should not be interpreted as a suspend request. */ info->syscall_break_signal = TRUE; if (!mono_threads_pthread_kill (info, mono_threads_posix_get_abort_signal ())) mono_threads_add_to_pending_operation_set (info); }
static gboolean begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { if (mono_threads_is_coop_enabled ()) { /* There's nothing else to do after we async request the thread to suspend */ mono_threads_add_to_pending_operation_set (info); return TRUE; } return mono_threads_core_begin_async_suspend (info, interrupt_kernel); }
gboolean mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { int sig = interrupt_kernel ? abort_signal_num : suspend_signal_num; if (!mono_threads_pthread_kill (info, sig)) { mono_threads_add_to_pending_operation_set (info); return TRUE; } return FALSE; }
/* This begins async resume. This function must do the following: - Install an async target if one was requested. - Notify the target to resume. */ gboolean mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) { int sig = mono_threads_suspend_get_restart_signal (); if (!mono_threads_pthread_kill (info, sig)) { mono_threads_add_to_pending_operation_set (info); return TRUE; } return FALSE; }
gboolean mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { DWORD id = mono_thread_info_get_tid (info); HANDLE handle; DWORD result; handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); g_assert (handle); result = SuspendThread (handle); THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret); if (result == (DWORD)-1) { CloseHandle (handle); return FALSE; } /* Suspend logic assumes thread is really suspended before continuing below. Surprisingly SuspendThread */ /* is just an async request to the scheduler, meaning that the suspended thread can continue to run */ /* user mode code until scheduler gets around and process the request. This will cause a thread state race */ /* in mono's thread state machine implementation on Windows. By requesting a threads context after issuing a */ /* suspended request, this will wait until thread is suspended and thread context has been collected */ /* and returned. */ CONTEXT context; context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { CloseHandle (handle); return FALSE; } /* We're in the middle of a self-suspend, resume and register */ if (!mono_threads_transition_finish_async_suspend (info)) { mono_threads_add_to_pending_operation_set (info); result = ResumeThread (handle); g_assert (result == 1); CloseHandle (handle); THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0); //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall return TRUE; } info->suspend_can_continue = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info, &context); THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res); if (info->suspend_can_continue) { if (interrupt_kernel) mono_win32_interrupt_wait (info, handle, id); } else { THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0); } CloseHandle (handle); return TRUE; }
gboolean mono_thread_info_begin_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { switch (mono_threads_transition_request_async_suspension (info)) { case AsyncSuspendAlreadySuspended: return TRUE; case AsyncSuspendWait: mono_threads_add_to_pending_operation_set (info); return TRUE; case AsyncSuspendInitSuspend: return mono_threads_core_begin_async_suspend (info, interrupt_kernel); default: g_assert_not_reached (); } }
gboolean mono_thread_info_begin_suspend (MonoThreadInfo *info) { switch (mono_threads_transition_request_async_suspension (info)) { case AsyncSuspendAlreadySuspended: case AsyncSuspendBlocking: return TRUE; case AsyncSuspendWait: mono_threads_add_to_pending_operation_set (info); return TRUE; case AsyncSuspendInitSuspend: return begin_async_suspend (info, FALSE); default: g_assert_not_reached (); } }
gboolean mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { DWORD id = mono_thread_info_get_tid (info); HANDLE handle; DWORD result; gboolean res; handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); g_assert (handle); result = SuspendThread (handle); THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret); if (result == (DWORD)-1) { CloseHandle (handle); return FALSE; } /* We're in the middle of a self-suspend, resume and register */ if (!mono_threads_transition_finish_async_suspend (info)) { mono_threads_add_to_pending_operation_set (info); result = ResumeThread (handle); g_assert (result == 1); CloseHandle (handle); THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0); //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall return TRUE; } res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info); THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res); if (res) { //FIXME do we need to QueueUserAPC on this case? if (interrupt_kernel) QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL); } else { mono_threads_transition_async_suspend_compensation (info); result = ResumeThread (handle); g_assert (result == 1); THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0); } CloseHandle (handle); return res; }
/* This begins async resume. This function must do the following: - Install an async target if one was requested. - Notify the target to resume. */ gboolean mono_threads_core_begin_async_resume (MonoThreadInfo *info) { mono_threads_add_to_pending_operation_set (info); return mono_threads_pthread_kill (info, restart_signal_num) == 0; }