diff options
Diffstat (limited to 'kernel/scheduler.c')
| -rw-r--r-- | kernel/scheduler.c | 222 |
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; +} |
