void act_reference( thread_act_t act) { if (act == NULL) return; act_lock(act); act_reference_locked(act); act_unlock(act); }
/* * Synchronize a thread operation with migration. * Called with nothing locked. * Returns with thr_act locked. */ thread_t act_lock_thread( thread_act_t thr_act) { /* * JMM - We have moved away from explicit RPC locks * and towards a generic migration approach. The wait * queue lock will be the point of synchronization for * the shuttle linkage when this is rolled out. Until * then, just lock the act. */ act_lock(thr_act); return (thr_act->thread); }
/* * Internal routine to terminate a thread. * Sometimes called with task already locked. */ kern_return_t thread_terminate_internal( register thread_act_t act) { kern_return_t result; thread_t thread; thread = act_lock_thread(act); if (!act->active) { act_unlock_thread(act); return (KERN_TERMINATED); } act_disable(act); result = act_abort(act, FALSE); /* * Make sure this thread enters the kernel * Must unlock the act, but leave the shuttle * captured in this act. */ if (thread != current_thread()) { act_unlock(act); if (thread_stop(thread)) thread_unstop(thread); else result = KERN_ABORTED; act_lock(act); } clear_wait(thread, act->started? THREAD_INTERRUPTED: THREAD_AWAKENED); act_unlock_thread(act); return (result); }
/* * thread_swapout_enqueue is called by thread_halt_self when it * processes AST_SWAPOUT to enqueue threads to be swapped out. * It must be called at normal interrupt priority for the * sake of the task_swapper_lock. * * There can be races with task swapin here. * First lock task and decrement swap_ast_waiting count, and if * it's 0, we can decrement the residence count on the task's map * and set the task's swap state to TASK_SW_OUT. */ void thread_swapout_enqueue(thread_act_t thr_act) { task_t task = thr_act->task; task_lock(task); /* * If the swap_state is not TASK_SW_GOING_OUT, then * task_swapin has beaten us to this operation, and * we have nothing to do. */ if (task->swap_state != TASK_SW_GOING_OUT) { task_unlock(task); return; } if (--task->swap_ast_waiting == 0) { vm_map_t map = task->map; task->swap_state = TASK_SW_OUT; task_unlock(task); mutex_lock(&map->s_lock); vm_map_res_deallocate(map); mutex_unlock(&map->s_lock); } else task_unlock(task); task_swapper_lock(); act_lock(thr_act); if (! (thr_act->swap_state & TH_SW_TASK_SWAPPING)) { /* * We lost a race with task_swapin(): don't enqueue. */ } else { queue_enter(&swapout_thread_q, thr_act, thread_act_t, swap_queue); thread_wakeup((event_t)&swapout_thread_q); } act_unlock(thr_act); task_swapper_unlock(); }
void act_deallocate( thread_act_t act) { task_t task; thread_t thread; void *task_proc; if (act == NULL) return; act_lock(act); if (--act->act_ref_count > 0) { act_unlock(act); return; } assert(!act->active); thread = act->thread; assert(thread != NULL); thread->top_act = NULL; act_unlock(act); task = act->task; task_lock(task); task_proc = task->bsd_info; { time_value_t user_time, system_time; thread_read_times(thread, &user_time, &system_time); time_value_add(&task->total_user_time, &user_time); time_value_add(&task->total_system_time, &system_time); queue_remove(&task->threads, act, thread_act_t, task_threads); act->task_threads.next = NULL; task->thread_count--; task->res_thread_count--; } task_unlock(task); act_prof_deallocate(act); ipc_thr_act_terminate(act); #ifdef MACH_BSD { extern void uthread_free(task_t, void *, void *, void *); void *ut = act->uthread; uthread_free(task, act, ut, task_proc); act->uthread = NULL; } #endif /* MACH_BSD */ task_deallocate(task); thread_deallocate(thread); }
/* * 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); } }