summaryrefslogtreecommitdiff
path: root/kernel/scheduler.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/scheduler.c')
-rw-r--r--kernel/scheduler.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/kernel/scheduler.c b/kernel/scheduler.c
new file mode 100644
index 0000000..4823276
--- /dev/null
+++ b/kernel/scheduler.c
@@ -0,0 +1,222 @@
+// http://hosted.cjmovie.net/TutMultitask.htm
+//
+//
+#define FOOLOS_MODULE_NAME "task"
+
+#include "kernel.h"
+#include "lib/logger/log.h" // logger facilities
+#include "mem.h"
+#include "asm/x86.h"
+
+#include "vmem.h"
+#include "syscalls.h"
+#include "fs/fs.h"
+#include "fs/ext2.h"
+
+#define MAX_TASKS 10
+
+static volatile int volatile current_task=-1;
+
+static volatile struct task_list_struct
+{
+ volatile int parent;
+ volatile bool active;
+ volatile uint32_t esp; // stack pointer of the task;
+ volatile pdirectory *vmem; // number of virtual memory table to switch to
+ volatile bool waiting;
+ volatile bool skipwait;
+ volatile uint32_t brk;
+
+}volatile task_list[MAX_TASKS];
+
+volatile int add_task(uint32_t esp, uint32_t vmem)
+{
+
+ for(int i=0;i<MAX_TASKS;i++)
+ {
+ if(task_list[i].active!=true)
+ {
+
+ task_list[i].parent=current_task;
+ task_list[i].vmem=vmem;
+ task_list[i].esp=esp;
+ task_list[i].active=true;
+ task_list[i].waiting=false;
+ task_list[i].skipwait=false;
+ task_list[i].brk=task_list[current_task].brk;
+ return i;
+ }
+ }
+
+ panic(FOOLOS_MODULE_NAME,"out of task slots!");
+}
+
+//
+// REMEMBER WE ARE INSIDE AN INTERRUPT HERE - DON'T WASTE TIME!
+//
+// oldesp - is the adress of the stack pointer when pit_interrupt_handler was entered.
+// registers have been pushed with pusha to this old stack.
+//
+// stack pointer was moved to the 16kb stack we have from multiboot.s
+//
+// we need to return a NEW stack pointer where popa will get the registers the new task requires
+//
+static int first=1;
+volatile uint32_t my_scheduler(uint32_t oldesp)
+{
+
+ // allows skipping scheduling from gdb
+ volatile int skippy=0;
+ if(skippy)return oldesp;
+
+ if(!first)
+ {
+ task_list[current_task].esp=oldesp;
+ }
+ first=0;
+
+ for(int i=0;i<MAX_TASKS;i++)
+ {
+ int pid=(current_task+1+i)%MAX_TASKS; // schedule round robin style
+
+ if(task_list[pid].active && !task_list[pid].waiting)
+ {
+// if(current_task!=pid)
+// log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"switch from %d to %d", current_task, pid);
+
+ current_task=pid;
+
+ vmem_set_dir(task_list[pid].vmem);
+ return task_list[pid].esp;
+ }
+
+ }
+
+ panic(FOOLOS_MODULE_NAME,"nothing to schedule!");
+}
+
+// this gets called by our clock interrupt regularly!
+volatile uint32_t task_switch_next(uint32_t oldesp)
+{
+ // check if multitasking has been started
+ if(current_task<0)return oldesp;
+ return my_scheduler(oldesp);
+}
+
+//TODO: free vmem too!
+//TODO: notify waiting parent when child finished;
+volatile uint32_t task_exit(uint32_t oldesp)
+{
+
+ task_list[current_task].active=false;
+ int parent_pid=task_list[current_task].parent;
+
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"[%d] exit ", current_task);
+
+ if(task_list[parent_pid].active)
+ {
+ if(task_list[parent_pid].waiting)
+ {
+
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"[%d] wake up", parent_pid);
+ task_list[parent_pid].waiting=false;
+ }
+ else
+ {
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"[%d] skipwait", parent_pid);
+ task_list[parent_pid].skipwait=true;
+ }
+
+ }
+
+ vmem_free_dir(task_list[current_task].vmem);
+
+ return my_scheduler(oldesp);
+
+}
+
+volatile uint32_t task_wait(uint32_t oldesp)
+{
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"[%d] wait", current_task);
+ if(task_list[current_task].skipwait)
+ {
+ task_list[current_task].skipwait=false;
+ }
+ else
+ {
+ task_list[current_task].waiting=true;
+ }
+ return my_scheduler(oldesp);
+}
+
+volatile uint32_t task_fork(uint32_t oldesp)
+{
+ int pid=add_task(oldesp,vmem_new_space_dir(task_list[current_task].vmem));
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"[%d] forked -> [%d] (free blocks remaining: %d )", current_task, pid,mem_get_free_blocks_count());
+ return pid;
+}
+
+// init task (root of all other tasks / processes) //
+volatile void scheduler_init(pdirectory *dir)
+{
+ current_task=0;
+
+ // this is our main task on slot 0
+ task_list[0].parent=0;
+ task_list[0].active=true;
+ task_list[0].waiting=false;
+ task_list[0].vmem=dir;
+ task_list[0].esp = kballoc(4); // 0; // will be set by next task_switch_next() call.
+
+ task_list[1].parent=0;
+ task_list[1].active=true;
+ task_list[1].waiting=false;
+ task_list[1].vmem=dir;
+ task_list[1].esp = kballoc(4); // fresh 16kb stack from here.
+
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"fresh esp on: 0x%08X",1,task_list[1].esp);
+ log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"fresh esp on: 0x%08X",0,task_list[0].esp);
+
+ task_pusha(task_list[1].esp); // pusha but to alternative location
+ task_pusha(task_list[0].esp); // pusha but to alternative location
+
+ /*
+ current_task=0;
+ unsigned esp, ebp, eax, ebx, ecx, edx;
+
+ asm(
+ "movl %%esp, %0;"
+ "movl %%ebp, %1;"
+ "movl %%eax, %2;"
+ "movl %%ebx, %3;"
+ "movl %%ecx, %4;"
+ "movl %%edx, %5;"
+ :"=r"(esp), "=r"(ebp), "=r"(eax), "=r"(ebx), "=r"(ecx), "=r"(edx)
+ );
+
+ // TODO: prepare stack so popa get's what it wants!
+ int i=task_fork(esp);
+ */
+
+ // finally enable interrrupts so the scheduler is called (by timer)
+ x86_sti();
+
+ // loop until scheduler kicks in and reschedules us...
+ while(1);
+
+}
+
+volatile int task_get_current_pid()
+{
+ return current_task;
+}
+
+volatile uint32_t task_get_brk()
+{
+ return task_list[current_task].brk;
+}
+
+volatile void task_set_brk(uint32_t brk)
+{
+ task_list[current_task].brk=brk;
+}