improved scheduling code
This commit is contained in:
parent
df0a944528
commit
d1bef0f8a1
11
kernel.c
11
kernel.c
@ -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:
|
||||
// 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
|
||||
li a0, 0x80
|
||||
csrrw zero, CSR_MSTATUS, a0 // write to mstatus
|
||||
// setup a0 to hold |trap tbl addr|mode|
|
||||
// len:| 30 | 2 |
|
||||
// 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
|
||||
csrrw zero, CSR_MTVEC, a0 // write a0 into mtvec csr entry
|
||||
// write
|
||||
csrw CSR_MTVEC, a0 // write to mtvec csr
|
||||
// enable interrupts in mstatus
|
||||
// mstatus[07] MPIE = 1 - we want to enable interrupts with mret
|
||||
li a0, 0x80
|
||||
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;
|
||||
|
||||
while (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;
|
||||
|
||||
// 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…
Reference in New Issue
Block a user