kernel/sched.c (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
#include "cedos/sched.h"
#include "cedos/process.h"
#include "cedos/mm/paging.h"
#include "cedos/drivers/console.h"
#include "cedos/core.h"
#include "cedos/interrupts.h"
#include "cedos/pit.h"
#include "cedos/pic.h"
#include "assembly.h"
#include "common.h"
#include "cedos/drivers/speaker.h"
void* const SCHED_STACK = (void*)(0xC0400000);
PROCESS* get_slot(void) {
static PROCESS free_slots[4];
static uint32_t index = 0;
return &(free_slots[index++]);
}
int sched_dispatcher(void);
/*!
* Executes a task.
*/
PROCESS_ID sched_exec(PHYS_ADDR page_dir, VIRT_ADDR eip, uint32_t eflags, VIRT_ADDR ebp) {
PHYS_ADDR tmp_page_dir = switch_page_dir(page_dir);
PROCESS* p = get_slot();
// set process context
p->page_dir = page_dir;
p->eip = sched_dispatcher;
p->ebp = ebp;
p->esp = ebp - sizeof(SCHED_FRAME);
p->eflags = eflags;
p->entry = (PROCESS_MAIN*)eip;
// setup stack
SCHED_FRAME* frame = (SCHED_FRAME*)(p->esp);
frame->eax = frame->ebx = frame->ecx = frame->edx = 0;
frame->esi = frame->edi = 0;
frame->ebp = p->ebp;
frame->esp = p->esp;
frame->eip = sched_dispatcher;
frame->cs = 0x8;
frame->eflags = eflags;
// TODO: add file descriptors for stdin, stdout and stderr
p->state = PSTATE_READY;
switch_page_dir(tmp_page_dir);
return add_process(p);
}
PROCESS_ID current_pid;
void sched_interrupt_c(SCHED_FRAME * volatile frame, uint32_t volatile ebp) {
//kpanic("SCHEDULER STACK INFO");
PROCESS* process = get_process(current_pid);
if (current_pid != 0) {
process->esp = (uint32_t)frame;
process->ebp = ebp;
process->eip = frame->eip;
process->eflags = frame->eflags;
}
// select next process
static int pid = 0;
pid = (pid + 1) % 4;
current_pid = pid;
printk("\n### SCHEDULER: SWITCH TO TASK %i\n", pid);
// prepare to return to process
switch_page_dir(process->page_dir);
process = get_process(current_pid);
frame = (volatile SCHED_FRAME*)(process->esp);
ebp = process->ebp;
frame->eip = process->eip;
frame->eflags = process->eflags;
// reset the timer
pit_setup_channel(PIT_CHANNEL_0, PIT_MODE_0, 0xFFFF);
pic1_eoi();
//if (current_pid == 2) outb(0xFE, 0x64);
}
void idle(void) {
printk(".");
while (1) { }
}
int sched_init(void) {
// create idle process
sched_exec(create_empty_page_dir(), idle, eflags() | (1 << 9), 0xC0200000);
return 1;
}
int sched_start(void) {
current_pid = get_process(0);
// perform the first timer interrupt manually
pic_unmask_interrupt(0);
INT(0x20);
}
void sched_yield(void) {
INT(0x20);
}
int sched_kill(PROCESS_ID pid) {
if (pid == current_pid) {
//remove_process(pid);
sched_yield();
return 1;
} else {
//remove_process(pid);
return 1;
}
}
int sched_dispatcher(void) {
printk("Dispatching process %i...\n", current_pid);
PROCESS* this = get_process(current_pid);
PROCESS_MAIN* entry = this->entry;
// enter the actual program
entry(0, (void*)0);
printk("Process %i terminated.\n", current_pid);
sched_kill(current_pid);
}