gboolean sgen_suspend_thread (SgenThreadInfo *info) { mach_msg_type_number_t num_state; thread_state_t state; kern_return_t ret; ucontext_t ctx; mcontext_t mctx; gpointer stack_start; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); do { ret = thread_suspend (info->client_info.info.native_handle); } while (ret == KERN_ABORTED); if (ret != KERN_SUCCESS) return FALSE; do { ret = mono_mach_arch_get_thread_state (info->client_info.info.native_handle, state, &num_state); } while (ret == KERN_ABORTED); if (ret != KERN_SUCCESS) return FALSE; mono_mach_arch_thread_state_to_mcontext (state, mctx); ctx.uc_mcontext = mctx; info->client_info.stopped_domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN); info->client_info.stopped_ip = (gpointer) mono_mach_arch_get_ip (state); info->client_info.stack_start = NULL; stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE; /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) { info->client_info.stack_start = stack_start; #ifdef USE_MONO_CTX mono_sigctx_to_monoctx (&ctx, &info->client_info.ctx); #else ARCH_COPY_SIGCTX_REGS (&info->client_info.regs, &ctx); #endif } else { g_assert (!info->client_info.stack_start); } /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, &ctx, NULL); SGEN_LOG (2, "thread %p stopped at %p stack_start=%p", (void*)(gsize)info->client_info.info.native_handle, info->client_info.stopped_ip, info->client_info.stack_start); binary_protocol_thread_suspend ((gpointer)mono_thread_info_get_tid (info), info->client_info.stopped_ip); return TRUE; }
gboolean sgen_suspend_thread (SgenThreadInfo *info) { DWORD id = mono_thread_info_get_tid (info); HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); CONTEXT context; DWORD result; g_assert (id != GetCurrentThreadId ()); g_assert (handle); result = SuspendThread (handle); if (result == (DWORD)-1) { fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr); CloseHandle (handle); return FALSE; } context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { g_assert_not_reached (); ResumeThread (handle); CloseHandle (handle); return FALSE; } g_assert (context.ContextFlags & CONTEXT_INTEGER); g_assert (context.ContextFlags & CONTEXT_CONTROL); CloseHandle (handle); info->stopped_ip = (gpointer)context.Eip; info->stack_start = (char*)context.Esp - REDZONE_SIZE; info->regs [0] = context.Edi; info->regs [1] = context.Esi; info->regs [2] = context.Ebx; info->regs [3] = context.Edx; info->regs [4] = context.Ecx; info->regs [5] = context.Eax; info->regs [6] = context.Ebp; info->regs [7] = context.Esp; info->stopped_regs = &info->regs; /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL); return TRUE; }
gboolean mono_sgen_suspend_thread (SgenThreadInfo *info) { DWORD id = mono_thread_info_get_tid (info); HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); CONTEXT context; DWORD result; g_assert (handle); result = SuspendThread (handle); g_assert (result != (DWORD)-1); if (result == (DWORD)-1) { CloseHandle (handle); return FALSE; } context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { g_assert_not_reached (); ResumeThread (handle); CloseHandle (handle); return FALSE; } g_assert (context.ContextFlags & CONTEXT_INTEGER); g_assert (context.ContextFlags & CONTEXT_CONTROL); CloseHandle (handle); info->stopped_domain = NULL; /* FIXME: implement! */ info->stopped_ip = (gpointer)context.Eip; info->stack_start = (char*)context.Esp - REDZONE_SIZE; info->regs [0] = context.Edi; info->regs [1] = context.Esi; info->regs [2] = context.Ebx; info->regs [3] = context.Edx; info->regs [4] = context.Ecx; info->regs [5] = context.Eax; info->regs [6] = context.Ebp; info->regs [7] = context.Esp; info->stopped_regs = &info->regs; /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL); return TRUE; }
gboolean mono_sgen_suspend_thread (SgenThreadInfo *info) { mach_msg_type_number_t num_state; thread_state_t state; kern_return_t ret; ucontext_t ctx; mcontext_t mctx; gpointer stack_start; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); ret = thread_suspend (info->mach_port); if (ret != KERN_SUCCESS) return FALSE; ret = mono_mach_arch_get_thread_state (info->mach_port, state, &num_state); if (ret != KERN_SUCCESS) return FALSE; mono_mach_arch_thread_state_to_mcontext (state, mctx); ctx.uc_mcontext = mctx; info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_domain_get_tls_offset ()); info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state); stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE; /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) { info->stack_start = stack_start; #ifdef USE_MONO_CTX mono_sigctx_to_monoctx (&ctx, &info->ctx); info->monoctx = &info->ctx; #else ARCH_COPY_SIGCTX_REGS (&info->regs, &ctx); info->stopped_regs = &info->regs; #endif } else { g_assert (!info->stack_start); } /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx); return TRUE; }
static void update_current_thread_stack (void *start) { int stack_guard = 0; SgenThreadInfo *info = mono_thread_info_current (); info->client_info.stack_start = align_pointer (&stack_guard); g_assert (info->client_info.stack_start); g_assert (info->client_info.stack_start >= info->client_info.stack_start_limit && info->client_info.stack_start < info->client_info.stack_end); #if !defined(MONO_CROSS_COMPILE) && MONO_ARCH_HAS_MONO_CONTEXT MONO_CONTEXT_GET_CURRENT (info->client_info.ctx); #else g_error ("Sgen STW requires a working mono-context"); #endif if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, NULL, &info->client_info.ctx); }
static void update_current_thread_stack (void *start) { int stack_guard = 0; #if !defined(USE_MONO_CTX) void *reg_ptr = cur_thread_regs; #endif SgenThreadInfo *info = mono_thread_info_current (); info->stack_start = align_pointer (&stack_guard); g_assert (info->stack_start >= info->stack_start_limit && info->stack_start < info->stack_end); #ifdef USE_MONO_CTX MONO_CONTEXT_GET_CURRENT (cur_thread_ctx); memcpy (&info->ctx, &cur_thread_ctx, sizeof (MonoContext)); if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL, &info->ctx); #else ARCH_STORE_REGS (reg_ptr); memcpy (&info->regs, reg_ptr, sizeof (info->regs)); if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL, NULL); #endif }
gboolean sgen_suspend_thread (SgenThreadInfo *info) { DWORD id = mono_thread_info_get_tid (info); HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); CONTEXT context; DWORD result; g_assert (id != GetCurrentThreadId ()); g_assert (handle); result = SuspendThread (handle); if (result == (DWORD)-1) { fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr); CloseHandle (handle); return FALSE; } context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { g_assert_not_reached (); ResumeThread (handle); CloseHandle (handle); return FALSE; } g_assert (context.ContextFlags & CONTEXT_INTEGER); g_assert (context.ContextFlags & CONTEXT_CONTROL); CloseHandle (handle); #if !defined(MONO_CROSS_COMPILE) #ifdef USE_MONO_CTX memset (&info->ctx, 0, sizeof (MonoContext)); #ifdef TARGET_AMD64 info->ctx.rip = context.Rip; info->ctx.rax = context.Rax; info->ctx.rcx = context.Rcx; info->ctx.rdx = context.Rdx; info->ctx.rbx = context.Rbx; info->ctx.rsp = context.Rsp; info->ctx.rbp = context.Rbp; info->ctx.rsi = context.Rsi; info->ctx.rdi = context.Rdi; info->ctx.r8 = context.R8; info->ctx.r9 = context.R9; info->ctx.r10 = context.R10; info->ctx.r11 = context.R11; info->ctx.r12 = context.R12; info->ctx.r13 = context.R13; info->ctx.r14 = context.R14; info->ctx.r15 = context.R15; info->stopped_ip = info->ctx.rip; info->stack_start = (char*)info->ctx.rsp - REDZONE_SIZE; #else info->ctx.edi = context.Edi; info->ctx.esi = context.Esi; info->ctx.ebx = context.Ebx; info->ctx.edx = context.Edx; info->ctx.ecx = context.Ecx; info->ctx.eax = context.Eax; info->ctx.ebp = context.Ebp; info->ctx.esp = context.Esp; info->stopped_ip = (gpointer)context.Eip; info->stack_start = (char*)context.Esp - REDZONE_SIZE; #endif #else info->regs [0] = context.Edi; info->regs [1] = context.Esi; info->regs [2] = context.Ebx; info->regs [3] = context.Edx; info->regs [4] = context.Ecx; info->regs [5] = context.Eax; info->regs [6] = context.Ebp; info->regs [7] = context.Esp; info->stopped_ip = (gpointer)context.Eip; info->stack_start = (char*)context.Esp - REDZONE_SIZE; #endif #endif /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, NULL, NULL); return TRUE; }
static void suspend_thread (SgenThreadInfo *info, void *context) { int stop_count; #ifndef USE_MONO_CTX gpointer regs [ARCH_NUM_REGS]; #endif MonoContext ctx; gpointer stack_start; info->client_info.stopped_domain = mono_domain_get (); info->client_info.signal = 0; stop_count = sgen_global_stop_count; /* duplicate signal */ if (0 && info->client_info.stop_count == stop_count) return; #ifdef USE_MONO_CTX if (context) { mono_sigctx_to_monoctx (context, &ctx); info->client_info.stopped_ip = MONO_CONTEXT_GET_IP (&ctx); stack_start = (((guint8 *) MONO_CONTEXT_GET_SP (&ctx)) - REDZONE_SIZE); } else { info->client_info.stopped_ip = NULL; stack_start = NULL; } #else info->client_info.stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL; stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL; #endif /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) { info->client_info.stack_start = stack_start; #ifdef USE_MONO_CTX if (context) { memcpy (&info->client_info.ctx, &ctx, sizeof (MonoContext)); } else { memset (&info->client_info.ctx, 0, sizeof (MonoContext)); } #else if (context) { ARCH_COPY_SIGCTX_REGS (regs, context); memcpy (&info->client_info.regs, regs, sizeof (info->client_info.regs)); } else { memset (&info->client_info.regs, 0, sizeof (info->client_info.regs)); } #endif } else { g_assert (!info->client_info.stack_start); } /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, context, NULL); SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer) (gsize) mono_native_thread_id_get ()); /* Block the restart signal. We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend, which might miss the signal and get stuck. */ pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL); /* notify the waiting thread */ SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr); info->client_info.stop_count = stop_count; /* wait until we receive the restart signal */ do { info->client_info.signal = 0; sigsuspend (&suspend_signal_mask); } while (info->client_info.signal != restart_signal_num); /* Unblock the restart signal. */ pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL); SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer) (gsize) mono_native_thread_id_get ()); /* notify the waiting thread */ SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr); }
static void suspend_thread (SgenThreadInfo *info, void *context) { int stop_count; #ifdef USE_MONO_CTX MonoContext monoctx; #else gpointer regs [ARCH_NUM_REGS]; #endif gpointer stack_start; g_assert (info->doing_handshake); info->stopped_domain = mono_domain_get (); info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL; stop_count = sgen_global_stop_count; /* duplicate signal */ if (0 && info->stop_count == stop_count) return; sgen_fill_thread_info_for_suspend (info); stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL; /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) { info->stack_start = stack_start; #ifdef USE_MONO_CTX if (context) { mono_sigctx_to_monoctx (context, &monoctx); info->monoctx = &monoctx; } else { info->monoctx = NULL; } #else if (context) { ARCH_COPY_SIGCTX_REGS (regs, context); info->stopped_regs = regs; } else { info->stopped_regs = NULL; } #endif } else { g_assert (!info->stack_start); } /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, context); DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)mono_native_thread_id_get ())); /* Block the restart signal. We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend, which might miss the signal and get stuck. */ pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL); /* notify the waiting thread */ MONO_SEM_POST (suspend_ack_semaphore_ptr); info->stop_count = stop_count; /* wait until we receive the restart signal */ do { info->signal = 0; sigsuspend (&suspend_signal_mask); } while (info->signal != restart_signal_num && info->doing_handshake); /* Unblock the restart signal. */ pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL); DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ())); /* notify the waiting thread */ MONO_SEM_POST (suspend_ack_semaphore_ptr); }
int mono_sgen_thread_handshake (int signum) { task_t task = current_task (); thread_port_t cur_thread = mach_thread_self (); thread_act_array_t thread_list; mach_msg_type_number_t num_threads; mach_msg_type_number_t num_state; thread_state_t state; kern_return_t ret; ucontext_t ctx; mcontext_t mctx; pthread_t exception_thread = mono_gc_get_mach_exception_thread (); SgenThreadInfo *info; gpointer regs [ARCH_NUM_REGS]; gpointer stack_start; int count, i; mono_mach_get_threads (&thread_list, &num_threads); for (i = 0, count = 0; i < num_threads; i++) { thread_port_t t = thread_list [i]; pthread_t pt = pthread_from_mach_thread_np (t); if (t != cur_thread && pt != exception_thread && !mono_sgen_is_worker_thread (pt)) { if (signum == suspend_signal_num) { ret = thread_suspend (t); if (ret != KERN_SUCCESS) { mach_port_deallocate (task, t); continue; } state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); ret = mono_mach_arch_get_thread_state (t, state, &num_state); if (ret != KERN_SUCCESS) { mach_port_deallocate (task, t); continue; } info = mono_sgen_thread_info_lookup (pt); /* Ensure that the runtime is aware of this thread */ if (info != NULL) { mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); mono_mach_arch_thread_state_to_mcontext (state, mctx); ctx.uc_mcontext = mctx; info->stopped_domain = mono_mach_arch_get_tls_value_from_thread (t, mono_pthread_key_for_tls (mono_domain_get_tls_key ())); info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state); stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE; /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) { info->stack_start = stack_start; ARCH_COPY_SIGCTX_REGS (regs, &ctx); info->stopped_regs = regs; } else { g_assert (!info->stack_start); } /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx); } } else { ret = thread_resume (t); if (ret != KERN_SUCCESS) { mach_port_deallocate (task, t); continue; } } count ++; mach_port_deallocate (task, t); } } mach_port_deallocate (task, cur_thread); return count; }
int mono_sgen_thread_handshake (int signum) { SgenThreadInfo *cur_thread = mono_sgen_thread_info_current (); mach_msg_type_number_t num_state; thread_state_t state; kern_return_t ret; ucontext_t ctx; mcontext_t mctx; SgenThreadInfo *info; gpointer stack_start; int count = 0; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); FOREACH_THREAD (info) { if (info == cur_thread || mono_sgen_is_worker_thread (info->id)) continue; if (signum == suspend_signal_num) { ret = thread_suspend (info->mach_port); if (ret != KERN_SUCCESS) continue; ret = mono_mach_arch_get_thread_state (info->mach_port, state, &num_state); if (ret != KERN_SUCCESS) continue; mono_mach_arch_thread_state_to_mcontext (state, mctx); ctx.uc_mcontext = mctx; info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_pthread_key_for_tls (mono_domain_get_tls_key ())); info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state); stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE; /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) { info->stack_start = stack_start; #ifdef USE_MONO_CTX mono_sigctx_to_monoctx (&ctx, &info->ctx); info->monoctx = &info->ctx; #else ARCH_COPY_SIGCTX_REGS (&info->regs, &ctx); info->stopped_regs = &info->regs; #endif } else { g_assert (!info->stack_start); } /* Notify the JIT */ if (mono_gc_get_gc_callbacks ()->thread_suspend_func) mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx); } else { ret = thread_resume (info->mach_port); if (ret != KERN_SUCCESS) continue; } count ++; } END_FOREACH_THREAD return count; }