Esempio n. 1
0
void
act_reference(
	thread_act_t	act)
{
	if (act == NULL)
		return;

	act_lock(act);
	act_reference_locked(act);
	act_unlock(act);
}
Esempio n. 2
0
/*
 * 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);
}
Esempio n. 3
0
/*
 * 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);
}
Esempio n. 4
0
/*
 *	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();
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
/*
 *	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);
	}
}