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()
{
init_ecall_table();
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();
// give control to the scheudler and start runnign user programs
scheduler_run_next();
}

@ -5,35 +5,32 @@ stack_bottom:
.space 4096
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
// tell the linker that init is a function located elsewhere
.extern init
.type init, @function
.extern trap_handle
.type trap_handle, @function
.global _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
// this is the setting loaded:
// [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
// mstatus[07] MPIE = 1 - we want to enable interrupts with mret
li a0, 0x80
csrrw zero, CSR_MSTATUS, a0 // write to mstatus
// 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
csrw CSR_MSTATUS, a0 // write to mstatus csr
.option push
.option norelax
// init sp and gp
la sp, stack_top
la gp, _gp
la gp, __global_pointer$
.option pop
// clear kernel bss section
mv a0, zero
@ -47,9 +44,13 @@ _start:
// halt machine after returning from init
li t0, -1
csrw CSR_HALT, t0
// if the halt CSR somehow didn't exit immediately trap execution in this infinite loop
1:
j 1b
.extern trap_handle
.type trap_handle, @function
.align 4
trap_vector:
// save all registers into the PCB struct

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

@ -29,6 +29,11 @@ void scheduler_run_next()
scheduler_switch_to(current_process);
}
void scheudler_init()
{
current_process = processes + PROCESS_COUNT - 1;
}
// try to return to a process
void scheduler_try_return_to(ProcessControlBlock* pcb)
{
@ -58,47 +63,59 @@ ProcessControlBlock* scheduler_select_free()
unsigned long long int mtime;
int timeout_available = false; // note if a timeout is available
if (current_process == NULL)
current_process = processes + PROCESS_COUNT - 1;
while (true) {
mtime = read_time();
ProcessControlBlock* pcb = current_process + 1;
if (pcb > processes + PROCESS_COUNT)
pcb = processes;
// 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)
pcb = processes;
while (pcb != current_process) {
// when we find a process which is ready to be scheduled, return it!
if (pcb->status == PROC_RDY)
return pcb;
// if it's sleeping, check if it is time to wake it up
if (pcb->status == PROC_WAIT_SLEEP) {
if (pcb->asleep_until < mtime) {
pcb->status = PROC_RDY;
return pcb;
}
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->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 < 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;
}
timeout_available = true;
}
}
pcb++;
if (pcb > processes + PROCESS_COUNT)
pcb = processes;
}
if (current_process->status == PROC_RDY) {
return current_process;
}
} while (pcb != current_process);
// when we finished iterating over all processes and no process can be scheduled we have a problem
if (timeout_available == false) {
// either process deadlock or no processes alive.
//TODO: handle missing executable thread
// either process deadlock without timeout or no processes alive.
//TODO: handle deadlocks by killing a process
dbgln("No thread active!", 17);
HALT(22);
}

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

Loading…
Cancel
Save