Beispiel #1
0
/* Thread0 scheduler ops (for processes that haven't linked in a full 2LS) */
static void thread0_sched_entry(void)
{
	if (current_uthread)
		run_current_uthread();
	else
		run_uthread(thread0_uth);
}
Beispiel #2
0
static void __pth_switch_cb(struct uthread *uthread, void *target)
{
	/* by not returning, this bypasses vcore entry and event checks, though when
	 * we pop back out of the 2LS, we'll check notif pending.  think about this
	 * if you put this into your 2LS. */
	current_uthread = NULL;
	run_uthread((struct uthread*)target);
	assert(0);
}
Beispiel #3
0
/* Called from vcore entry.  Options usually include restarting whoever was
 * running there before or running a new thread.  Events are handled out of
 * event.c (table of function pointers, stuff like that). */
static void __attribute__((noreturn)) pth_sched_entry(void)
{
	uint32_t vcoreid = vcore_id();
	if (current_uthread) {
		/* Prep the pthread to run any pending posix signal handlers registered
         * via pthread_kill once it is restored. */
		__pthread_prep_for_pending_posix_signals((pthread_t)current_uthread);
		/* Run the thread itself */
		run_current_uthread();
		assert(0);
	}
	/* no one currently running, so lets get someone from the ready queue */
	struct pthread_tcb *new_thread = NULL;
	/* Try to get a thread.  If we get one, we'll break out and run it.  If not,
	 * we'll try to yield.  vcore_yield() might return, if we lost a race and
	 * had a new event come in, one that may make us able to get a new_thread */
	do {
		handle_events(vcoreid);
		__check_preempt_pending(vcoreid);
		mcs_pdr_lock(&queue_lock);
		new_thread = TAILQ_FIRST(&ready_queue);
		if (new_thread) {
			TAILQ_REMOVE(&ready_queue, new_thread, tq_next);
			TAILQ_INSERT_TAIL(&active_queue, new_thread, tq_next);
			threads_active++;
			threads_ready--;
			mcs_pdr_unlock(&queue_lock);
			/* If you see what looks like the same uthread running in multiple
			 * places, your list might be jacked up.  Turn this on. */
			printd("[P] got uthread %08p on vc %d state %08p flags %08p\n",
			       new_thread, vcoreid,
			       ((struct uthread*)new_thread)->state,
			       ((struct uthread*)new_thread)->flags);
			break;
		}
		mcs_pdr_unlock(&queue_lock);
		/* no new thread, try to yield */
		printd("[P] No threads, vcore %d is yielding\n", vcore_id());
		/* TODO: you can imagine having something smarter here, like spin for a
		 * bit before yielding (or not at all if you want to be greedy). */
		if (can_adjust_vcores)
			vcore_yield(FALSE);
		if (!parlib_wants_to_be_mcp)
			sys_yield(FALSE);
	} while (1);
	assert(new_thread->state == PTH_RUNNABLE);
	/* Prep the pthread to run any pending posix signal handlers registered
     * via pthread_kill once it is restored. */
	__pthread_prep_for_pending_posix_signals(new_thread);
	/* Run the thread itself */
	run_uthread((struct uthread*)new_thread);
	assert(0);
}
Beispiel #4
0
/* Thread0 scheduler ops (for processes that haven't linked in a full 2LS) */
static void thread0_sched_entry(void)
{
	/* TODO: support signal handling whenever we run a uthread */
	if (current_uthread) {
		uthread_prep_pending_signals(current_uthread);
		run_current_uthread();
		assert(0);
	}
	while (1) {
		if (!thread0_info.is_blocked) {
			uthread_prep_pending_signals(thread0_uth);
			run_uthread(thread0_uth);
			assert(0);
		}
		sys_yield(FALSE);
		handle_events(0);
	}
}
Beispiel #5
0
/* Called from vcore entry.  Options usually include restarting whoever was
 * running there before or running a new thread.  Events are handled out of
 * event.c (table of function pointers, stuff like that). */
void __attribute__((noreturn)) pth_sched_entry(void)
{
	uint32_t vcoreid = vcore_id();
	if (current_uthread) {
		run_current_uthread();
		assert(0);
	}
	/* no one currently running, so lets get someone from the ready queue */
	struct pthread_tcb *new_thread = NULL;
	struct mcs_lock_qnode local_qn = {0};
	/* For now, let's spin and handle events til we get a thread to run.  This
	 * will help catch races, instead of only having one core ever run a thread
	 * (if there is just one, etc).  Also, we don't need the EVENT_IPIs for this
	 * to work (since we poll handle_events() */
	while (!new_thread) {
		handle_events(vcoreid);
		mcs_lock_notifsafe(&queue_lock, &local_qn);
		new_thread = TAILQ_FIRST(&ready_queue);
		if (new_thread) {
			TAILQ_REMOVE(&ready_queue, new_thread, next);
			TAILQ_INSERT_TAIL(&active_queue, new_thread, next);
			threads_active++;
			threads_ready--;
		}
		mcs_unlock_notifsafe(&queue_lock, &local_qn);
	}
	/* Instead of yielding, you could spin, turn off the core, set an alarm,
	 * whatever.  You want some logic to decide this.  Uthread code wil have
	 * helpers for this (like how we provide run_uthread()) */
	if (!new_thread) {
		/* Note, we currently don't get here (due to the while loop) */
		printd("[P] No threads, vcore %d is yielding\n", vcore_id());
		/* Not actually yielding - just spin for now, so we can get syscall
		 * unblocking events */
		vcore_idle();
		//sys_yield(0);
		assert(0);
	}
	assert(((struct uthread*)new_thread)->state != UT_RUNNING);
	run_uthread((struct uthread*)new_thread);
	assert(0);
}