[MULTITASKING] Context switching and scheduler

This commit is contained in:
2016-11-05 19:55:54 +01:00
parent 1f06c0bcf1
commit 5e8fbcbb78
9 changed files with 288 additions and 0 deletions

70
kernel/proc/scheduler.c Normal file
View File

@@ -0,0 +1,70 @@
#include <scheduler.h>
#include <list.h>
#include <debug.h>
LIST(thread_t, ready_queue);
thread_t *scheduler_th;
thread_t *last_thread = 0;
#define get_last_thread() (last_thread)
#define set_last_thread(new) (last_thread = (new))
void scheduler_insert(thread_t *th)
{
// Append thread to the ready queue and prepare it for running
LIST_APPEND(ready_queue, th, ready_queue);
th->state = THREAD_STATE_READY;
}
void scheduler_remove(thread_t *th)
{
// Remove thread from the ready queue
LIST_REMOVE(ready_queue, th, ready_queue);
}
thread_t *scheduler_next()
{
// Get the next thread from the ready queue
if(!LIST_EMPTY(ready_queue))
{
thread_t *th = LIST_FIRST(ready_queue);
scheduler_remove(th);
return th;
}
return 0;
}
void scheduler()
{
while(1)
{
thread_t *old = 0, *new = 0;
if((old = get_last_thread()))
{
if(old->state == THREAD_STATE_RUNNING)
{
old->state = THREAD_STATE_READY;
scheduler_insert(old);
}
}
while(!(new = scheduler_next()));
new->state = THREAD_STATE_RUNNING;
set_last_thread(new);
switch_thread(scheduler_th, new);
}
}
void schedule()
{
// This function handles swithing to the next thread in the ready queue
thread_t *old = get_current_thread();
switch_thread(old, scheduler_th);
}
void scheduler_init()
{
LIST_HEAD_INIT(ready_queue);
scheduler_th = new_thread(scheduler);
}

28
kernel/proc/swtch.S Normal file
View File

@@ -0,0 +1,28 @@
.intel_syntax noprefix
.global swtch
swtch:
# void swtch(uint64_t *old, uint64_t *new)
# Switches stacks preserving callee preserved registers according to System V ABI
push rbp
mov rbp, rsp
push r15
push r14
push r13
push r12
push rbx
push rbp
cmp rdi, 0x0
jz .switch_in
mov [rdi], rsp
.switch_in:
mov rsp, [rsi]
pop rbp
pop rbx
pop r12
pop r13
pop r14
pop r15
leaveq
ret

47
kernel/proc/thread.c Normal file
View File

@@ -0,0 +1,47 @@
#include <thread.h>
#include <stdint.h>
#include <mem.h>
#include <list.h>
#include <debug.h>
thread_t *current_thread = 0;
uint64_t tid = 1;
thread_t *new_thread(void (*func)(void))
{
// Set up original stack of thread
thread_stack_t *stack = kcalloc(1, sizeof(thread_stack_t));
thread_t *th = &stack->tcb;
stack->function_address = (uint64_t)func;
stack->RBP = (uint64_t)&stack->zero_frame;
th->tid = tid++;
th->state = THREAD_STATE_READY;
th->stack_pointer = (uint64_t)&stack->RBP;
LIST_INIT(th, ready_queue);
return th;
}
void switch_thread(thread_t *old, thread_t *new)
{
set_current_thread(new);
uint64_t *old_stack = (old)?&old->stack_pointer:0;
swtch(old_stack, &new->stack_pointer);
}
void free_thread(thread_t *th)
{
if(th->state == THREAD_STATE_RUNNING || th->state == THREAD_STATE_READY)
{
debug_error("Trying to free a live thread!\n");
for(;;);
}
thread_stack_t *stack = incptr(th, -offsetof(thread_stack_t, tcb));
kfree(stack);
}