improved scheduling code

master
Anton Lydike 3 years ago
parent df0a944528
commit d1bef0f8a1

@ -17,12 +17,15 @@ extern void memset(unsigned int, void*, void*);
extern void init() extern void init()
{ {
init_ecall_table();
dbgln("Kernel started!", 15); dbgln("Kernel started!", 15);
// initialize scheduler
scheudler_init();
// initialize tabel for associating ecall codes with their handlers
init_ecall_table();
// read supplied binaries, this will call malloc_init with the memory layout
// then it will create a new process for each loaded binary
read_binary_table(); read_binary_table();
// give control to the scheudler and start runnign user programs
scheduler_run_next(); scheduler_run_next();
} }

@ -5,35 +5,32 @@ stack_bottom:
.space 4096 .space 4096
stack_top: stack_top:
// put the startup code in a special section so that the linker can position it at the start of the binary
.section .text._start .section .text._start
// tell the linker that init is a function located elsewhere
.extern init .extern init
.type init, @function .type init, @function
.extern trap_handle
.type trap_handle, @function
.global _start .global _start
_start: _start:
// setup mie register, enable timer and software interrupts targeting machine mode
// mie[7] MTIE = 1 - enable timer interrupts
// mie[3] MSIE = 1 - enable software interrupts
li a0, 0x88
csrw CSR_MIE, a0 // write to mie csr
// load trap vector address into a0
la a0, trap_vector
csrw CSR_MTVEC, a0 // write to mtvec csr
// enable interrupts in mstatus // enable interrupts in mstatus
// this is the setting loaded: // mstatus[07] MPIE = 1 - we want to enable interrupts with mret
// [07] MPIE = 1 - we want to enable interrupts with mret
// [03] MIE = 0 - we don't want interrupts now
// [11:12] MPP = 0 - we want to return into user mode
// all other bits should be zero
li a0, 0x80 li a0, 0x80
csrrw zero, CSR_MSTATUS, a0 // write to mstatus csrw CSR_MSTATUS, a0 // write to mstatus csr
// setup a0 to hold |trap tbl addr|mode|
// len:| 30 | 2 |
la a0, trap_vector
csrrw zero, CSR_MTVEC, a0 // write a0 into mtvec csr entry
// write
.option push .option push
.option norelax .option norelax
// init sp and gp // init sp and gp
la sp, stack_top la sp, stack_top
la gp, _gp la gp, __global_pointer$
.option pop .option pop
// clear kernel bss section // clear kernel bss section
mv a0, zero mv a0, zero
@ -47,9 +44,13 @@ _start:
// halt machine after returning from init // halt machine after returning from init
li t0, -1 li t0, -1
csrw CSR_HALT, t0 csrw CSR_HALT, t0
// if the halt CSR somehow didn't exit immediately trap execution in this infinite loop
1: 1:
j 1b j 1b
.extern trap_handle
.type trap_handle, @function
.align 4 .align 4
trap_vector: trap_vector:
// save all registers into the PCB struct // save all registers into the PCB struct

@ -13,6 +13,7 @@ enum error_code {
ENOMEM = 3, // not enough memory ENOMEM = 3, // not enough memory
ENOBUFS = 4, // no space left in buffer ENOBUFS = 4, // no space left in buffer
ESRCH = 5, // no such process ESRCH = 5, // no such process
EABORT = 6
}; };
/* /*

@ -29,6 +29,11 @@ void scheduler_run_next()
scheduler_switch_to(current_process); scheduler_switch_to(current_process);
} }
void scheudler_init()
{
current_process = processes + PROCESS_COUNT - 1;
}
// try to return to a process // try to return to a process
void scheduler_try_return_to(ProcessControlBlock* pcb) void scheduler_try_return_to(ProcessControlBlock* pcb)
{ {
@ -58,47 +63,59 @@ ProcessControlBlock* scheduler_select_free()
unsigned long long int mtime; unsigned long long int mtime;
int timeout_available = false; // note if a timeout is available int timeout_available = false; // note if a timeout is available
if (current_process == NULL)
current_process = processes + PROCESS_COUNT - 1;
while (true) { while (true) {
mtime = read_time(); mtime = read_time();
ProcessControlBlock* pcb = current_process + 1; // start at the last scheduled process
ProcessControlBlock* pcb = current_process;
// iterate once over the whole list
do {
// get next pcb
pcb++;
// wrap around the end of the list
if (pcb > processes + PROCESS_COUNT) if (pcb > processes + PROCESS_COUNT)
pcb = processes; pcb = processes;
while (pcb != current_process) { // when we find a process which is ready to be scheduled, return it!
if (pcb->status == PROC_RDY) if (pcb->status == PROC_RDY)
return pcb; return pcb;
// if it's sleeping, check if it is time to wake it up
if (pcb->status == PROC_WAIT_SLEEP) { if (pcb->status == PROC_WAIT_SLEEP) {
if (pcb->asleep_until < mtime) { if (pcb->asleep_until < mtime) {
pcb->status = PROC_RDY;
return pcb; return pcb;
} }
timeout_available = true; timeout_available = true;
} }
// if it's waiting for another process, check if the process exited
// or if is waiting with a timeout, tell it the timeout expired
if (pcb->status == PROC_WAIT_PROC) { if (pcb->status == PROC_WAIT_PROC) {
if (pcb->waiting_for_process != NULL &&
pcb->waiting_for_process->status == PROC_DEAD) {
// the requested process exited, so we can set the status code and
pcb->regs[REG_A0] = pcb->waiting_for_process->exit_code;
pcb->regs[REG_A0+1] = 0;
pcb->status = PROC_RDY;
return pcb;
}
if (pcb->asleep_until != 0) { if (pcb->asleep_until != 0) {
if (pcb->asleep_until < mtime) { if (pcb->asleep_until < mtime) {
//TODO: set process return args! // if the timeout ran out, set an error code
pcb->regs[REG_A0 + 1] = EABORT;
pcb->status = PROC_RDY;
return pcb; return pcb;
} }
timeout_available = true; timeout_available = true;
} }
} }
pcb++; } while (pcb != current_process);
if (pcb > processes + PROCESS_COUNT)
pcb = processes;
}
if (current_process->status == PROC_RDY) {
return current_process;
}
// when we finished iterating over all processes and no process can be scheduled we have a problem
if (timeout_available == false) { if (timeout_available == false) {
// either process deadlock or no processes alive. // either process deadlock without timeout or no processes alive.
//TODO: handle missing executable thread //TODO: handle deadlocks by killing a process
dbgln("No thread active!", 17); dbgln("No thread active!", 17);
HALT(22); HALT(22);
} }

@ -8,6 +8,7 @@
extern ProcessControlBlock processes[PROCESS_COUNT]; extern ProcessControlBlock processes[PROCESS_COUNT];
// scheduler methods // scheduler methods
void scheudler_init();
ProcessControlBlock* scheduler_select_free(); ProcessControlBlock* scheduler_select_free();
void set_next_interrupt(); void set_next_interrupt();
void __attribute__((noreturn)) scheduler_run_next(); void __attribute__((noreturn)) scheduler_run_next();

Loading…
Cancel
Save