BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / c530261a6ef76632384504044bc0b0519a33938e / task / scheduler.c

// Related

Nucleus

Barry Task queues and full scheduling c530261 (3 years, 3 months ago)
/*
 * This file contains the scheduler.  It implements a basic task switching
 * routine, as well as the schedule() function.  The scheduler can be called
 * from anywhere, and will switch to the next task decided by the scheduler
 * rules.  If it cannot find a task to schedule, it just idles until one becomes
 * available.  This avoids the need for an idle task.
 */

#include <nucleus/panic.h>
#include <nucleus/task.h>

TaskQueue *readyQueue[HIGHEST];

/* Read the EIP */
static uintptr_t
read_eip(void)
{
	uintptr_t eip;
	asm volatile("movl 4(%%ebp), %0" : "=r" (eip));
	return eip;
}

/* Switch to a task */
static void
switch_to_task(Task *task)
{
	uintptr_t esp, ebp, eip;
	asm volatile("mov %%esp, %0" : "=r" (esp));
	asm volatile("mov %%ebp, %0" : "=r" (ebp));
	eip = (uintptr_t) &&end;

	current->esp = esp;
	current->ebp = ebp;
	current->eip = eip;
	put(current);
	current = task; /* Use the passed reference */
	esp = current->esp;
	ebp = current->ebp;
	eip = current->eip;

	asm volatile (
		"cli;"
		"movl %0, %%ecx;"
		"movl %1, %%esp;"
		"movl %2, %%ebp;"
		"movl %3, %%cr3;"
		"sti;"
		"jmp *%%ecx"
		:: "g" (eip), "g" (esp), "g" (ebp), "g" (current->pageDir)
	);
end:
}

/* Schedule the next task */
void
schedule(void)
{
	Task *task = current;

	/* Next schedulable task */
	if (readyQueue[NORMAL]->start) {
		task = pop_from_queue(readyQueue[NORMAL]);
		task->state = RUNNING;
		if (current->state == RUNNING) {
			current->state = READY;
			add_to_queue(readyQueue[current->priority], current);
		}
		switch_to_task(task);
	/* Idle */
	} else if (current->state != RUNNING) {
		current = NULL;
		asm volatile("sti");
		while (!readyQueue[NORMAL]->start)
			asm volatile("hlt");
		asm volatile("cli");
		current = task;
		task = pop_from_queue(readyQueue[NORMAL]);
		task->state = RUNNING;
		switch_to_task(task);
	}
}

/* Initialise the scheduler */
void
init_scheduler(void)
{
	enum Priority p;
	for (p = NONE; p <= HIGHEST; p++)
		readyQueue[p] = new(&taskQueueType);
}