gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoNativeThreadId thread_id, MonoNativeThreadHandle thread_handle) { kern_return_t ret; mach_msg_type_number_t num_state; thread_state_t state; ucontext_t ctx; mcontext_t mctx; guint32 domain_key, jit_key; MonoJitTlsData *jit_tls; void *domain; #if defined (MONO_ARCH_ENABLE_MONO_LMF_VAR) guint32 lmf_key; #endif /*Zero enough state to make sure the caller doesn't confuse itself*/ tctx->valid = FALSE; tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL; tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL; tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); ret = mono_mach_arch_get_thread_state (thread_handle, state, &num_state); if (ret != KERN_SUCCESS) return FALSE; mono_mach_arch_thread_state_to_mcontext (state, mctx); ctx.uc_mcontext = mctx; mono_sigctx_to_monoctx (&ctx, &tctx->ctx); domain_key = mono_domain_get_tls_offset (); jit_key = mono_get_jit_tls_key (); jit_tls = mono_mach_arch_get_tls_value_from_thread (thread_id, jit_key); domain = mono_mach_arch_get_tls_value_from_thread (thread_id, domain_key); /*Thread already started to cleanup, can no longer capture unwind state*/ if (!jit_tls) return FALSE; g_assert (domain); #if defined (MONO_ARCH_ENABLE_MONO_LMF_VAR) lmf_key = mono_get_lmf_tls_offset (); tctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_mach_arch_get_tls_value_from_thread (thread_id, lmf_key);; #else tctx->unwind_data [MONO_UNWIND_DATA_LMF] = jit_tls ? jit_tls->lmf : NULL; #endif tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain; tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls; tctx->valid = TRUE; return TRUE; }
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 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; }
gboolean mono_threads_core_begin_async_resume (MonoThreadInfo *info) { kern_return_t ret; if (info->async_target) { MonoContext tmp = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx; mach_msg_type_number_t num_state; thread_state_t state; ucontext_t uctx; mcontext_t mctx; mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, info->async_target, info->user_data); info->user_data = NULL; info->async_target = (void (*)(void *)) info->user_data; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); ret = mono_mach_arch_get_thread_state (info->native_handle, state, &num_state); if (ret != KERN_SUCCESS) return FALSE; mono_mach_arch_thread_state_to_mcontext (state, mctx); #ifdef TARGET_ARM64 g_assert_not_reached (); #else uctx.uc_mcontext = mctx; #endif mono_monoctx_to_sigctx (&tmp, &uctx); mono_mach_arch_mcontext_to_thread_state (mctx, state); ret = mono_mach_arch_set_thread_state (info->native_handle, state, num_state); if (ret != KERN_SUCCESS) return FALSE; } ret = thread_resume (info->native_handle); THREADS_SUSPEND_DEBUG ("RESUME %p -> %d\n", (void*)info->native_handle, ret); return ret == KERN_SUCCESS; }
gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoNativeThreadId thread_id, MonoNativeThreadHandle thread_handle) { kern_return_t ret; mach_msg_type_number_t num_state; thread_state_t state; ucontext_t ctx; mcontext_t mctx; guint32 domain_key, jit_key; MonoJitTlsData *jit_tls; void *domain; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); ret = mono_mach_arch_get_thread_state (thread_handle, state, &num_state); if (ret != KERN_SUCCESS) return FALSE; mono_mach_arch_thread_state_to_mcontext (state, mctx); ctx.uc_mcontext = mctx; mono_sigctx_to_monoctx (&ctx, &tctx->ctx); domain_key = mono_domain_get_tls_offset (); jit_key = mono_pthread_key_for_tls (mono_get_jit_tls_key ()); jit_tls = mono_mach_arch_get_tls_value_from_thread (thread_id, jit_key); domain = mono_mach_arch_get_tls_value_from_thread (thread_id, domain_key); /*Thread already started to cleanup, can no longer capture unwind state*/ if (!jit_tls) return FALSE; g_assert (domain); tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain; tctx->unwind_data [MONO_UNWIND_DATA_LMF] = jit_tls ? jit_tls->lmf : NULL; tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls; tctx->valid = TRUE; return TRUE; }
gboolean mono_threads_core_resume (MonoThreadInfo *info) { kern_return_t ret; if (info->async_target) { MonoContext tmp = info->suspend_state.ctx; mach_msg_type_number_t num_state; thread_state_t state; ucontext_t uctx; mcontext_t mctx; mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, info->async_target, info->user_data); info->async_target = info->user_data = NULL; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); ret = mono_mach_arch_get_thread_state (info->native_handle, state, &num_state); if (ret != KERN_SUCCESS) return FALSE; mono_mach_arch_thread_state_to_mcontext (state, mctx); #ifdef TARGET_ARM64 g_assert_not_reached (); #else uctx.uc_mcontext = mctx; #endif mono_monoctx_to_sigctx (&tmp, &uctx); mono_mach_arch_mcontext_to_thread_state (mctx, state); ret = mono_mach_arch_set_thread_state (info->native_handle, state, num_state); if (ret != KERN_SUCCESS) return FALSE; } ret = thread_resume (info->native_handle); return ret == KERN_SUCCESS; }
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; }