Mercurial > lcfOS
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; +} +