BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / task / schedule.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/task/schedule.c b/task/schedule.c
new file mode 100644
index 0000000..1c00576
--- /dev/null
+++ b/task/schedule.c
@@ -0,0 +1,182 @@
+/*
+ * This file controls the Kernel's scheduler.  It decides when a new task must
+ * be scheduled, and which tasks can actually be scheduled.
+ */
+
+#include <stdint.h>
+#include "../proc/proc.h"
+#include "../mem/paging.h"
+#include "task.h"
+
+uintptr_t read_eip(void);
+void context_switch(uintptr_t eip, page_dir_t phys,
+                    uintptr_t ebp, uintptr_t esp);
+void handle_signals(void);
+
+TaskQueue readyQueue, tasks;
+Task *currentTask[MAX_CPUS];
+
+/* 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 = read_eip();
+	if (eip == 0x10032004) /* Magic number */
+		return;
+
+	acquire(&current->lock);
+	current->eip = eip;
+	current->esp = esp;
+	current->ebp = ebp;
+	release(&current->lock);
+	current = task;
+	eip = current->eip;
+	esp = current->esp;
+	ebp = current->ebp;
+
+	context_switch(eip, current->pageDir, ebp, esp);
+	/* UNREACHED */
+
+	/*
+	 * This code actually returns to the read_eip() call above.  This is due
+	 * to how the call works.  The context switch jumps to the address
+	 * stored in the eip variable.  This address is the return address of
+	 * the read_eip() call.  The context_switch() function sets the return
+	 * value before jumping, so it appears as though read_eip() returned
+	 * that value.  The code uses the magic number 0x10032004 to tell when
+	 * this is occurring and just returns early.
+	 */
+}
+
+/* Find task by ID */
+Task *
+find_task(pid_t tid)
+{
+	Task *task;
+	for (task = tasks.start; task && task->tid != tid; task = task->tnext);
+	return task;
+}
+
+/* Add a task to a task queue */
+void
+add_to_queue(TaskQueue *queue, Task *task)
+{
+	if (!queue->start) {
+		queue->start = task;
+		queue->end = task;
+	} else {
+		queue->end->next = task;
+		queue->end = task;
+	}
+	task->next = NULL;
+}
+
+/* Remove a task from a task queue */
+void
+remove_from_queue(TaskQueue *queue, Task *task)
+{
+	/* Start of list */
+	if (queue->start == task) {
+		queue->start = task->next;
+		if (!queue->start)
+			queue->end = NULL;
+		return;
+	}
+
+	/* Search */
+	Task *prev;
+	for (prev = queue->start; prev->next; prev = prev->next)
+		if (prev->next == task)
+			break;
+	if (prev->next) {
+		prev->next = task->next;
+		if (queue->end == task)
+			queue->end = prev;
+	}
+}
+
+/* Remove the first task from a task queue */
+Task *
+pop_from_queue(TaskQueue *queue)
+{
+	Task *head = queue->start;
+	queue->start = head->next;
+	if (!queue->start)
+		queue->end = NULL;
+	return head;
+}
+
+/* Block a task */
+void
+block_task(int reason)
+{
+	acquire(&current->lock);
+	current->state = reason;
+	release(&current->lock);
+	schedule();
+}
+
+/* Unblock a task */
+void
+unblock_task(Task *task)
+{
+	if (task->state == READY || task->state == RUNNING)
+		return;
+	task->state = READY;
+	if (!readyQueue.start || task->priority > current->priority) {
+		acquire(&readyQueue.lock);
+		task->next = readyQueue.start;
+		readyQueue.start = task;
+		if (!readyQueue.end)
+			readyQueue.end = task;
+		release(&readyQueue.lock);
+	} else {
+		add_to_queue(&readyQueue, task);
+	}
+}
+
+/* Schedule next task */
+void
+schedule(void)
+{
+	Task *task = current;
+
+	/* Next schedulable task */
+	if (readyQueue.start) {
+		acquire(&readyQueue.lock);
+		task = readyQueue.start;
+		readyQueue.start = task->next;
+		if (!readyQueue.start)
+			readyQueue.end = NULL;
+		task->state = RUNNING;
+		task->next = NULL;
+		if (current->state == RUNNING) {
+			current->state = READY;
+			add_to_queue(&readyQueue, current);
+		}
+		release(&readyQueue.lock);
+		switch_to_task(task);
+	/* Idle task */
+	} else if (current->state != RUNNING) {
+		current = NULL;
+		asm volatile("sti");
+		while (!readyQueue.start)
+			asm volatile("hlt");
+		asm volatile("cli");
+		current = task;
+		acquire(&readyQueue.lock);
+		task = readyQueue.start;
+		readyQueue.start = task->next;
+		if (!readyQueue.start)
+			readyQueue.end = NULL;
+		task->state = RUNNING;
+		task->next = NULL;
+		release(&readyQueue.lock);
+		switch_to_task(task);
+	}
+
+	handle_signals();
+}