Thread suspension, aborts, and state access
Per-thread user and internal suspend counts, waits for a remote thread to stop, abort and abort-safe handling, and the generic register-state access path. These operations are separate from replying to an outstanding Mach exception.
thread_hold source
Suspend execution of the specified thread.
This is a recursive-style suspension of the thread, a count of
suspends is maintained.
Called with thread mutex held.
void thread_hold(thread_t thread) { if (thread->suspend_count++ == 0) { task_t task = get_threadtask(thread); thread_set_apc_ast(thread); assert(thread->suspend_parked == FALSE); KDBG_RELEASE(MACHDBG_CODE(DBG_MACH_SUSPENSION, MACH_THREAD_SUSPEND) | DBG_FUNC_NONE, thread->thread_id, thread->user_stop_count, task->pidsuspended); } }
thread_release source
Decrement internal suspension count, setting thread
runnable when count falls to zero.
Because the wait is abortsafe, we can't be guaranteed that the thread
is currently actually waiting even if suspend_parked is set.
Called with thread mutex held.
void thread_release(thread_t thread) { assertf(thread->suspend_count > 0, "thread %p over-resumed", thread); /* fail-safe on non-assert builds */ if (thread->suspend_count == 0) { return; } if (--thread->suspend_count == 0) { if (!thread->started) { thread_start(thread); } else if (thread->suspend_parked) { thread->suspend_parked = FALSE; thread_wakeup_thread(&thread->suspend_count, thread); } KDBG_RELEASE(MACHDBG_CODE(DBG_MACH_SUSPENSION, MACH_THREAD_RESUME) | DBG_FUNC_NONE, thread->thread_id); } }
thread_suspend source · thread_suspend reference
kern_return_t thread_suspend(thread_t thread) { kern_return_t result = KERN_SUCCESS; if (thread == THREAD_NULL || get_threadtask(thread) == kernel_task) { return KERN_INVALID_ARGUMENT; } thread_mtx_lock(thread); if (thread->active) { if (thread->user_stop_count++ == 0) { thread_hold(thread); } } else { result = KERN_TERMINATED; } thread_mtx_unlock(thread); if (thread != current_thread() && result == KERN_SUCCESS) { thread_wait(thread, FALSE); } return result; }
thread_resume source · thread_resume reference
kern_return_t thread_resume(thread_t thread) { kern_return_t result = KERN_SUCCESS; if (thread == THREAD_NULL || get_threadtask(thread) == kernel_task) { return KERN_INVALID_ARGUMENT; } thread_mtx_lock(thread); if (thread->active) { if (thread->user_stop_count > 0) { if (--thread->user_stop_count == 0) { thread_release(thread); } } else { result = KERN_FAILURE; } } else { result = KERN_TERMINATED; } thread_mtx_unlock(thread); return result; }
thread_abort source · thread_abort reference
kern_return_t thread_abort( thread_t thread) { kern_return_t result = KERN_SUCCESS; if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } thread_mtx_lock(thread); if (thread->active) { act_abort(thread); clear_wait(thread, THREAD_INTERRUPTED); } else { result = KERN_TERMINATED; } thread_mtx_unlock(thread); return result; }
thread_abort_safely source · thread_abort_safely reference
kern_return_t thread_abort_safely( thread_t thread) { kern_return_t result = KERN_SUCCESS; if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } thread_mtx_lock(thread); if (thread->active) { spl_t s = splsched(); thread_lock(thread); if (!thread->at_safe_point || clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) { if (!(thread->sched_flags & TH_SFLAG_ABORT)) { thread->sched_flags |= TH_SFLAG_ABORTED_MASK; thread_set_apc_ast_locked(thread); thread_depress_abort_locked(thread); } } thread_unlock(thread); splx(s); } else { result = KERN_TERMINATED; } … more in source
thread_get_state_internal source
static inline kern_return_t thread_get_state_internal( thread_t thread, int flavor, thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count, /*IN/OUT*/ thread_set_status_flags_t flags) { kern_return_t result = KERN_SUCCESS; boolean_t to_user = !!(flags & TSSF_TRANSLATE_TO_USER); if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } thread_mtx_lock(thread); if (thread->active) { if (thread != current_thread()) { thread_hold(thread); thread_mtx_unlock(thread); if (thread_stop(thread, FALSE)) { thread_mtx_lock(thread); result = machine_thread_get_state( thread, flavor, state, state_count); thread_unstop(thread); } else { thread_mtx_lock(thread); … more in source
thread_get_state source · thread_get_state reference
kern_return_t thread_get_state( thread_t thread, int flavor, thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count) /*IN/OUT*/ { return thread_get_state_internal(thread, flavor, state, state_count, TSSF_FLAGS_NONE); }
thread_get_state_to_user source
kern_return_t thread_get_state_to_user( thread_t thread, int flavor, thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count) /*IN/OUT*/ { return thread_get_state_internal(thread, flavor, state, state_count, TSSF_TRANSLATE_TO_USER); }
thread_set_state_internal source
Change thread's machine-dependent state. Called with nothing
locked. Returns same way.
static inline kern_return_t thread_set_state_internal( thread_t thread, int flavor, thread_state_t state, mach_msg_type_number_t state_count, thread_state_t old_state, mach_msg_type_number_t old_state_count, thread_set_status_flags_t flags) { kern_return_t result = KERN_SUCCESS; boolean_t from_user = !!(flags & TSSF_TRANSLATE_TO_USER); if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } /* * process will be crashed with kGUARD_EXC_THREAD_SET_STATE * if thread_set_state_allowed() return false. */ if (!thread_set_state_allowed(thread, flavor, flags)) { return KERN_NO_ACCESS; } thread_mtx_lock(thread); if (thread->active) { if (from_user) { result = machine_thread_state_convert_from_user(thread, flavor, … more in source
thread_set_state source · thread_set_state reference
kern_return_t thread_set_state( thread_t thread, int flavor, thread_state_t state, mach_msg_type_number_t state_count) { return thread_set_state_internal(thread, flavor, state, state_count, NULL, 0, TSSF_FLAGS_NONE); }
thread_set_state_from_user source
kern_return_t thread_set_state_from_user( thread_t thread, int flavor, thread_state_t state, mach_msg_type_number_t state_count) { return thread_set_state_internal(thread, flavor, state, state_count, NULL, 0, TSSF_TRANSLATE_TO_USER | TSSF_CHECK_ENTITLEMENT); }