static kern_return_t thread_create_internal2( task_t task, thread_t *new_thread, boolean_t from_user) { kern_return_t result; thread_t thread; if (task == TASK_NULL || task == kernel_task) return (KERN_INVALID_ARGUMENT); result = thread_create_internal(task, -1, (thread_continue_t)thread_bootstrap_return, TH_OPTION_NONE, &thread); if (result != KERN_SUCCESS) return (result); thread->user_stop_count = 1; thread_hold(thread); if (task->suspend_count > 0) thread_hold(thread); if (from_user) extmod_statistics_incr_thread_create(task); task_unlock(task); lck_mtx_unlock(&tasks_threads_lock); *new_thread = thread; return (KERN_SUCCESS); }
kern_return_t thread_create_workq( task_t task, thread_continue_t thread_return, thread_t *new_thread) { kern_return_t result; thread_t thread; if (task == TASK_NULL || task == kernel_task) return (KERN_INVALID_ARGUMENT); result = thread_create_internal(task, -1, thread_return, TH_OPTION_NOCRED | TH_OPTION_NOSUSP, &thread); if (result != KERN_SUCCESS) return (result); thread->user_stop_count = 1; thread_hold(thread); if (task->suspend_count > 0) thread_hold(thread); task_unlock(task); lck_mtx_unlock(&tasks_threads_lock); *new_thread = thread; return (KERN_SUCCESS); }
kern_return_t thread_create( task_t task, thread_t *new_thread) { kern_return_t result; thread_t thread; if (task == TASK_NULL || task == kernel_task) return (KERN_INVALID_ARGUMENT); result = thread_create_internal(task, -1, (thread_continue_t)thread_bootstrap_return, &thread); if (result != KERN_SUCCESS) return (result); thread->user_stop_count = 1; thread_hold(thread); if (task->suspend_count > 0) thread_hold(thread); task_unlock(task); mutex_unlock(&tasks_threads_lock); *new_thread = thread; return (KERN_SUCCESS); }
/* * Change thread's machine-dependent state. Called with nothing * locked. Returns same way. */ kern_return_t thread_set_state( register thread_act_t act, int flavor, thread_state_t state, mach_msg_type_number_t state_count) { kern_return_t result = KERN_SUCCESS; thread_t thread; if (act == THR_ACT_NULL || act == current_act()) return (KERN_INVALID_ARGUMENT); thread = act_lock_thread(act); if (!act->active) { act_unlock_thread(act); return (KERN_TERMINATED); } thread_hold(act); for (;;) { thread_t thread1; if ( thread == THREAD_NULL || thread->top_act != act ) break; act_unlock_thread(act); if (!thread_stop(thread)) { result = KERN_ABORTED; (void)act_lock_thread(act); thread = THREAD_NULL; break; } thread1 = act_lock_thread(act); if (thread1 == thread) break; thread_unstop(thread); thread = thread1; } if (result == KERN_SUCCESS) result = machine_thread_set_state(act, flavor, state, state_count); if ( thread != THREAD_NULL && thread->top_act == act ) thread_unstop(thread); thread_release(act); act_unlock_thread(act); return (result); }
kern_return_t thread_dup( register thread_act_t target) { kern_return_t result = KERN_SUCCESS; thread_act_t self = current_act(); thread_t thread; if (target == THR_ACT_NULL || target == self) return (KERN_INVALID_ARGUMENT); thread = act_lock_thread(target); if (!target->active) { act_unlock_thread(target); return (KERN_TERMINATED); } thread_hold(target); for (;;) { thread_t thread1; if ( thread == THREAD_NULL || thread->top_act != target ) break; act_unlock_thread(target); if (!thread_stop(thread)) { result = KERN_ABORTED; (void)act_lock_thread(target); thread = THREAD_NULL; break; } thread1 = act_lock_thread(target); if (thread1 == thread) break; thread_unstop(thread); thread = thread1; } if (result == KERN_SUCCESS) result = machine_thread_dup(self, target); if ( thread != THREAD_NULL && thread->top_act == target ) thread_unstop(thread); thread_release(target); act_unlock_thread(target); return (result); }
/* * thread_stop_freeze * Block the thread in the kernel and freeze the processor set. * return value: * TRUE - the thread has blocked interruptibly, is stopped, and * the processor set assignment is frozen * FALSE - the thread is no longer in the processor set, so it * isn't stopped, and the processor set assignment * is released. */ int thread_stop_freeze( thread_t thread, processor_set_t pset ) { thread_act_t thr_act; spl_t s; /* * hold it, and wait for it to stop. */ thr_act = thread_lock_act(thread); thread_hold(thr_act); act_unlock_thread(thr_act); thread_stop(thread); s = splsched(); wake_lock(thread); while( thread->state & (TH_RUN|TH_UNINT) ) { thread->wake_active = TRUE; assert_wait((event_t)&thread->wake_active, FALSE); wake_unlock(thread); splx(s); thread_block( (void (*)(void)) 0 ); (void) splsched(); wake_lock(thread); } /* * Now, the thread has blocked uninterruptibly; freeze the * assignment and make sure it's still part of the processor set. */ wake_unlock(thread); thread_freeze(thread); thread_lock(thread); /* * if the processor set has changed, release the freeze and * then unstop it. */ if( thread->processor_set != pset ) { thread_unlock(thread); splx(s); thread_unfreeze(thread); thread_unstop(thread); return FALSE; } thread_unlock(thread); splx(s); return TRUE; }
kern_return_t thread_get_state( register thread_t thread, int flavor, thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count) /*IN/OUT*/ { kern_return_t result = KERN_SUCCESS; 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); result = KERN_ABORTED; } thread_release(thread); } else result = machine_thread_get_state( thread, flavor, state, state_count); } else if (thread->inspection) { result = machine_thread_get_state( thread, flavor, state, state_count); } else result = KERN_TERMINATED; thread_mtx_unlock(thread); return (result); }
/* * Change thread's machine-dependent state. Called with nothing * locked. Returns same way. */ static kern_return_t thread_set_state_internal( register thread_t thread, int flavor, thread_state_t state, mach_msg_type_number_t state_count, boolean_t from_user) { kern_return_t result = KERN_SUCCESS; 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, TRUE)) { thread_mtx_lock(thread); result = machine_thread_set_state( thread, flavor, state, state_count); thread_unstop(thread); } else { thread_mtx_lock(thread); result = KERN_ABORTED; } thread_release(thread); } else result = machine_thread_set_state( thread, flavor, state, state_count); } else result = KERN_TERMINATED; if ((result == KERN_SUCCESS) && from_user) extmod_statistics_incr_thread_set_state(thread); thread_mtx_unlock(thread); return (result); }
kern_return_t thread_dup2( thread_t source, thread_t target) { kern_return_t result = KERN_SUCCESS; uint32_t active = 0; if (source == THREAD_NULL || target == THREAD_NULL || target == source) return (KERN_INVALID_ARGUMENT); thread_mtx_lock(source); active = source->active; thread_mtx_unlock(source); if (!active) { return KERN_TERMINATED; } thread_mtx_lock(target); if (target->active || target->inspection) { thread_hold(target); thread_mtx_unlock(target); if (thread_stop(target, TRUE)) { thread_mtx_lock(target); result = machine_thread_dup(source, target); if (source->affinity_set != AFFINITY_SET_NULL) thread_affinity_dup(source, target); thread_unstop(target); } else { thread_mtx_lock(target); result = KERN_ABORTED; } thread_release(target); } else result = KERN_TERMINATED; thread_mtx_unlock(target); return (result); }
/* * Change thread's machine-dependent userspace TSD base. * Called with nothing locked. Returns same way. */ kern_return_t thread_set_tsd_base( thread_t thread, mach_vm_offset_t tsd_base) { kern_return_t result = KERN_SUCCESS; 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, TRUE)) { thread_mtx_lock(thread); result = machine_thread_set_tsd_base(thread, tsd_base); thread_unstop(thread); } else { thread_mtx_lock(thread); result = KERN_ABORTED; } thread_release(thread); } else result = machine_thread_set_tsd_base(thread, tsd_base); } else result = KERN_TERMINATED; thread_mtx_unlock(thread); return (result); }
kern_return_t thread_dup( register thread_t target) { thread_t self = current_thread(); kern_return_t result = KERN_SUCCESS; if (target == THREAD_NULL || target == self) return (KERN_INVALID_ARGUMENT); thread_mtx_lock(target); if (target->active) { thread_hold(target); thread_mtx_unlock(target); if (thread_stop(target, TRUE)) { thread_mtx_lock(target); result = machine_thread_dup(self, target); if (self->affinity_set != AFFINITY_SET_NULL) thread_affinity_dup(self, target); thread_unstop(target); } else { thread_mtx_lock(target); result = KERN_ABORTED; } thread_release(target); } else result = KERN_TERMINATED; thread_mtx_unlock(target); return (result); }
kern_return_t thread_suspend(thread_t thread) { kern_return_t result = KERN_SUCCESS; if (thread == THREAD_NULL || thread->task == 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); }
/* * task_swap_swapout_thread: [exported] * * Executes as a separate kernel thread. * Its job is to swap out threads that have been halted by AST_SWAPOUT. */ void task_swap_swapout_thread(void) { thread_act_t thr_act; thread_t thread, nthread; task_t task; int s; thread_swappable(current_act(), FALSE); stack_privilege(current_thread()); spllo(); while (TRUE) { task_swapper_lock(); while (! queue_empty(&swapout_thread_q)) { queue_remove_first(&swapout_thread_q, thr_act, thread_act_t, swap_queue); /* * If we're racing with task_swapin, we need * to make it safe for it to do remque on the * thread, so make its links point to itself. * Allowing this ugliness is cheaper than * making task_swapin search the entire queue. */ act_lock(thr_act); queue_init((queue_t) &thr_act->swap_queue); act_unlock(thr_act); task_swapper_unlock(); /* * Wait for thread's RUN bit to be deasserted. */ thread = act_lock_thread(thr_act); if (thread == THREAD_NULL) act_unlock_thread(thr_act); else { boolean_t r; thread_reference(thread); thread_hold(thr_act); act_unlock_thread(thr_act); r = thread_stop_wait(thread); nthread = act_lock_thread(thr_act); thread_release(thr_act); thread_deallocate(thread); act_unlock_thread(thr_act); if (!r || nthread != thread) { task_swapper_lock(); continue; } } task = thr_act->task; task_lock(task); /* * we can race with swapin, which would set the * state to TASK_SW_IN. */ if ((task->swap_state != TASK_SW_OUT) && (task->swap_state != TASK_SW_GOING_OUT)) { task_unlock(task); task_swapper_lock(); TASK_STATS_INCR(task_sw_race_in_won); if (thread != THREAD_NULL) thread_unstop(thread); continue; } nthread = act_lock_thread(thr_act); if (nthread != thread || thr_act->active == FALSE) { act_unlock_thread(thr_act); task_unlock(task); task_swapper_lock(); TASK_STATS_INCR(task_sw_act_inactive); if (thread != THREAD_NULL) thread_unstop(thread); continue; } s = splsched(); if (thread != THREAD_NULL) thread_lock(thread); /* * Thread cannot have been swapped out yet because * TH_SW_TASK_SWAPPING was set in AST. If task_swapin * beat us here, we either wouldn't have found it on * the queue, or the task->swap_state would have * changed. The synchronization is on the * task's swap_state and the task_lock. * The thread can't be swapped in any other way * because its task has been swapped. */ assert(thr_act->swap_state & TH_SW_TASK_SWAPPING); assert(thread == THREAD_NULL || !(thread->state & (TH_SWAPPED_OUT|TH_RUN))); assert((thr_act->swap_state & TH_SW_STATE) == TH_SW_IN); /* assert(thread->state & TH_HALTED); */ /* this also clears TH_SW_TASK_SWAPPING flag */ thr_act->swap_state = TH_SW_GOING_OUT; if (thread != THREAD_NULL) { if (thread->top_act == thr_act) { thread->state |= TH_SWAPPED_OUT; /* * Once we unlock the task, things can happen * to the thread, so make sure it's consistent * for thread_swapout. */ } thread->ref_count++; thread_unlock(thread); thread_unstop(thread); } splx(s); act_locked_act_reference(thr_act); act_unlock_thread(thr_act); task_unlock(task); thread_swapout(thr_act); /* do the work */ if (thread != THREAD_NULL) thread_deallocate(thread); act_deallocate(thr_act); task_swapper_lock(); } assert_wait((event_t)&swapout_thread_q, FALSE); task_swapper_unlock(); thread_block((void (*)(void)) 0); } }