diff cos/kernel/task.c @ 25:d3c4bf3720a3

Beginning of multitasking
author windel
date Tue, 27 Dec 2011 13:31:38 +0100
parents
children 47b7df514243
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cos/kernel/task.c	Tue Dec 27 13:31:38 2011 +0100
@@ -0,0 +1,98 @@
+#include "kernel.h"
+
+// global variables:
+uint64_t next_pid = 1;
+task_t* ready_queue = 0; // Head of the queue of tasks.
+task_t* current_task = 0; // Pointer to the currently running task.
+
+void initialize_tasking()
+{
+   next_pid = 1;
+}
+
+/*
+  Create a new task with some loaded program.
+*/
+void new_task()
+{
+   task_t* newtask = (task_t*)kmalloc(sizeof(task_t));
+   newtask->pid = next_pid++;
+   newtask->rip = 0;
+   newtask->next = 0;
+
+   // Append the new task to the ready queue:
+   task_t* task = ready_queue;
+   while (task->next != 0)
+   {
+      task = task->next;
+   }
+   task->next = newtask;
+}
+
+/* Fork function duplicates the process */
+void task_fork()
+{
+   asm volatile("cli"); // Disable interrupts
+   task_t *parent_task = current_task;
+
+   // Create new task:
+   task_t *new_task = (task_t*)kmalloc(sizeof(task_t));
+   new_task->pid = next_pid++;
+   new_task->rsp = 0;
+   new_task->rbp = 0;
+   new_task->rip = 0;
+   new_task->next = 0;
+
+   // Append to the queue:
+   task_t* tmp_task = ready_queue;
+   while (tmp_task->next != 0)
+   {
+      tmp_task = tmp_task->next;
+   }
+   tmp_task->next = new_task;
+
+   uint64_t rip = read_rip();
+
+   if (current_task == parent_task)
+   {
+      uint64_t rbp, rsp;
+      asm volatile("mov %%rsp, %0" : "=r"(rsp));
+      asm volatile("mov %%rbp, %0" : "=r"(rbp));
+      new_task->rip = rip;
+
+      asm volatile("sti");
+   }
+}
+
+/*
+  Scheduler function that switches tasks for multi tasking.
+*/
+void task_scheduler()
+{
+   if (current_task == 0)
+   {
+      return;
+   }
+
+   uint64_t rbp, rsp, rip;
+
+   rip = 0;
+   rsp = 0;
+   rbp = 0;
+
+   current_task->rip = rip; // TODO
+   current_task->rsp = rsp;
+   current_task->rbp = rbp;
+
+   // Select next task:
+   current_task = current_task->next;
+   if (current_task == 0)
+   {
+      current_task = ready_queue;
+   }
+
+   // Set the rbp, rsp and rip registers:
+   rsp = current_task->rsp;
+   rbp = current_task->rbp;
+}
+