mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-30 05:58:22 +00:00
kernel threads
kernel threads and preemptive multitasking
This commit is contained in:
+171
-23
@@ -1,49 +1,197 @@
|
||||
#include <kernel/sched.h>
|
||||
#include <arch/cls.h>
|
||||
#include <kernel/sched.h>
|
||||
#include <arch/spinlock.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <arch/mmu.h>
|
||||
#include <kernel/pmm.h>
|
||||
#include <kernel/timer.h>
|
||||
|
||||
thread_t* queue;
|
||||
thread_t* blocked;
|
||||
#define THREAD_QUANTUM 10000
|
||||
|
||||
static thread_t* next_thread(){
|
||||
// queue 0: interrupt threads
|
||||
// queue 1: kernel threads
|
||||
// queue 2: user threads
|
||||
|
||||
#define QUEUE_COUNT 3
|
||||
|
||||
sched_queue queues[QUEUE_COUNT];
|
||||
sched_queue running;
|
||||
sched_queue blocked;
|
||||
|
||||
static thread_t* allocthread(proc_t* proc, state_t state, pid_t tid, size_t kstacksize){
|
||||
|
||||
thread_t* thread = queue;
|
||||
thread_t* thread = alloc(sizeof(thread_t));
|
||||
if(!thread)
|
||||
return NULL;
|
||||
|
||||
while(1){
|
||||
|
||||
while(thread != NULL && thread->state != THREAD_STATE_WAITING)
|
||||
thread = thread->next;
|
||||
|
||||
if(!thread)
|
||||
asm("hlt"); // wait until something happens that would allow a thread to be scheduled
|
||||
thread->regs = alloc(sizeof(arch_regs));
|
||||
|
||||
if(!thread->regs){
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// XXX use alloc() when it's better
|
||||
|
||||
size_t pagec = kstacksize / PAGE_SIZE + 1;
|
||||
|
||||
thread->kernelstackbase = pmm_hhdmalloc(pagec);
|
||||
|
||||
|
||||
if(!thread->kernelstackbase){
|
||||
free(thread->regs);
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
thread->proc = proc;
|
||||
thread->state = state;
|
||||
thread->tid = tid;
|
||||
thread->kernelstack = thread->kernelstackbase + kstacksize;
|
||||
thread->stacksize = kstacksize;
|
||||
|
||||
return thread;
|
||||
|
||||
}
|
||||
|
||||
static void queue_add(sched_queue* queue, thread_t* thread){
|
||||
thread->next = NULL;
|
||||
thread->prev = queue->end;
|
||||
if(queue->end)
|
||||
queue->end->next = thread;
|
||||
queue->end = thread;
|
||||
if(!queue->start)
|
||||
queue->start = thread;
|
||||
|
||||
}
|
||||
|
||||
static void queue_remove(sched_queue* queue, thread_t* thread){
|
||||
|
||||
if(thread->next)
|
||||
thread->next->prev = thread->prev;
|
||||
else
|
||||
queue->end = thread->prev;
|
||||
|
||||
if(thread->prev)
|
||||
thread->prev->next = thread->next;
|
||||
else
|
||||
queue->start = thread->next;
|
||||
|
||||
}
|
||||
|
||||
static thread_t* getnext(){
|
||||
|
||||
thread_t* thread = NULL;
|
||||
|
||||
for(int i = 0; i < QUEUE_COUNT && thread == NULL; ++i){
|
||||
|
||||
spinlock_acquire(&queues[i].lock);
|
||||
|
||||
if(queues[i].start){
|
||||
thread = queues[i].start;
|
||||
queue_remove(&queues[i], thread);
|
||||
}
|
||||
|
||||
spinlock_release(&queues[i].lock);
|
||||
|
||||
}
|
||||
|
||||
if(thread){
|
||||
|
||||
spinlock_acquire(&running.lock);
|
||||
|
||||
queue_add(&running, thread);
|
||||
|
||||
spinlock_release(&running.lock);
|
||||
|
||||
}
|
||||
|
||||
return thread;
|
||||
|
||||
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) static void sched_switch(thread_t* thread){
|
||||
|
||||
int a = 0;
|
||||
|
||||
void sched_timerhook(arch_regs* regs){
|
||||
|
||||
thread_t* current = arch_getcls()->thread;
|
||||
|
||||
sched_queue* currentqueue = &queues[current->priority];
|
||||
|
||||
|
||||
spinlock_acquire(&running.lock);
|
||||
|
||||
queue_remove(&running, current);
|
||||
|
||||
spinlock_release(&running.lock);
|
||||
|
||||
|
||||
memcpy(current->regs, regs, sizeof(arch_regs));
|
||||
|
||||
|
||||
spinlock_acquire(¤tqueue->lock);
|
||||
|
||||
queue_add(currentqueue, current);
|
||||
|
||||
spinlock_release(¤tqueue->lock);
|
||||
|
||||
|
||||
thread_t* next = getnext();
|
||||
|
||||
if(next)
|
||||
memcpy(regs, next->regs, sizeof(arch_regs));
|
||||
|
||||
timer_add(&arch_getcls()->schedreq, THREAD_QUANTUM, false);
|
||||
|
||||
arch_getcls()->thread = next;
|
||||
|
||||
}
|
||||
|
||||
static void switch_thread(thread_t* thread){
|
||||
|
||||
thread_t* current = arch_getcls()->thread;
|
||||
|
||||
// if we don't have to change processes don't waste time
|
||||
|
||||
if(current->proc != thread->proc){
|
||||
|
||||
// change address spaces and all
|
||||
|
||||
// TODO change proc specific stuff
|
||||
|
||||
}
|
||||
|
||||
|
||||
arch_setkernelstack(thread->kernelstack);
|
||||
|
||||
arch_switchcontext(thread->regs);
|
||||
|
||||
|
||||
__builtin_unreachable();
|
||||
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void sched_timerhook(arch_regs* c){
|
||||
|
||||
thread_t* current = arch_getcls()->thread;
|
||||
thread_t* sched_newkthread(void* ip, size_t stacksize, bool run, int prio){
|
||||
thread_t* thread = allocthread(NULL, THREAD_STATE_WAITING, 0, stacksize);
|
||||
|
||||
memcpy(current->regs, c, sizeof(arch_regs));
|
||||
if(!thread) return NULL;
|
||||
|
||||
;
|
||||
thread->priority = prio;
|
||||
|
||||
__builtin_unreachable();
|
||||
arch_regs_setupkernel(thread->regs, ip, thread->kernelstack, true);
|
||||
|
||||
if(run)
|
||||
queue_add(&queues[prio], thread);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
void sched_init(){
|
||||
arch_getcls()->thread = allocthread(NULL, THREAD_STATE_RUNNING, 0, 0);
|
||||
arch_getcls()->thread->priority = THREAD_PRIORITY_KERNEL;
|
||||
|
||||
timer_req* req = &arch_getcls()->schedreq;
|
||||
|
||||
req->func = sched_timerhook;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -43,7 +43,7 @@ void timer_stop(){
|
||||
}
|
||||
}
|
||||
|
||||
void timer_add(timer_req* req, size_t us){
|
||||
void timer_add(timer_req* req, size_t us, bool start){
|
||||
|
||||
size_t remainingticks = arch_cputimer_stop();
|
||||
|
||||
@@ -55,8 +55,8 @@ void timer_add(timer_req* req, size_t us){
|
||||
if(!iter){
|
||||
arch_getcls()->timerfirstreq = req;
|
||||
req->next = NULL;
|
||||
arch_cputimer_fire(req->ticks);
|
||||
printf("ticks3: %lu", req->ticks);
|
||||
if(start);
|
||||
arch_cputimer_fire(req->ticks);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ void timer_add(timer_req* req, size_t us){
|
||||
if(iter->ticks > req->ticks){
|
||||
req->next = arch_getcls()->timerfirstreq;
|
||||
arch_getcls()->timerfirstreq = req;
|
||||
arch_cputimer_fire(req->ticks);
|
||||
printf("ticks2: %lu", req->ticks);
|
||||
if(start)
|
||||
arch_cputimer_fire(req->ticks);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ void timer_add(timer_req* req, size_t us){
|
||||
req->next = iter->next;
|
||||
iter->next = req;
|
||||
|
||||
printf("ticks: %lu", arch_getcls()->timerfirstreq->ticks);
|
||||
arch_cputimer_fire(arch_getcls()->timerfirstreq->ticks);
|
||||
if(start)
|
||||
arch_cputimer_fire(arch_getcls()->timerfirstreq->ticks);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user