feat(kernel): add preemptive round-robin thread scheduler
This commit is contained in:
1 parent
ad8ae808e6
commit
455e81de5e
2 files changed
+228
No files matched your search
+183
@@ -0,0 +1,183 @@
|
||||
#include "sched.h"
|
||||
#include "isr.h"
|
||||
#include "heap.h"
|
||||
#include "string.h"
|
||||
#include "ports.h"
|
||||
#include "gdt.h"
|
||||
#include "tss.h"
|
||||
#include "pit.h"
|
||||
#include "console.h"
|
||||
#include "paging.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#define maxThreads 16
|
||||
#define threadStackSize 16384
|
||||
|
||||
static Thread threads[maxThreads];
|
||||
static uint32 threadTotal;
|
||||
static uint32 currentIndex;
|
||||
static bool schedulerActive;
|
||||
|
||||
void schedInit(void)
|
||||
{
|
||||
threadTotal = 1;
|
||||
currentIndex = 0;
|
||||
|
||||
threads[0].id = 0;
|
||||
threads[0].name = "idle";
|
||||
threads[0].state = threadRunning;
|
||||
threads[0].rsp = 0;
|
||||
threads[0].stackBase = 0;
|
||||
threads[0].kernelStackTop = 0;
|
||||
threads[0].sleepUntil = 0;
|
||||
threads[0].brk = 0;
|
||||
vfsFdInit(threads[0].fds);
|
||||
}
|
||||
|
||||
uint32 threadCreate(const char* name, ThreadEntry entry)
|
||||
{
|
||||
uint32 slot = threadTotal;
|
||||
threadTotal++;
|
||||
|
||||
uint64 stackBase = (uint64)kmalloc(threadStackSize);
|
||||
uint64 stackTop = (stackBase + threadStackSize) & ~15ull;
|
||||
|
||||
Registers* frame = (Registers*)(stackTop - sizeof(Registers));
|
||||
memset(frame, 0, sizeof(Registers));
|
||||
frame->rip = (uint64)entry;
|
||||
frame->cs = kernelCodeSelector;
|
||||
frame->rflags = 0x202;
|
||||
frame->rsp = stackTop;
|
||||
frame->ss = kernelDataSelector;
|
||||
|
||||
threads[slot].id = slot;
|
||||
threads[slot].name = name;
|
||||
threads[slot].state = threadRunnable;
|
||||
threads[slot].stackBase = stackBase;
|
||||
threads[slot].kernelStackTop = stackTop;
|
||||
threads[slot].rsp = (uint64)frame;
|
||||
threads[slot].sleepUntil = 0;
|
||||
threads[slot].brk = 0;
|
||||
vfsFdInit(threads[slot].fds);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
uint32 threadCreateUser(const char* name, uint64 entry, uint64 userStackTop)
|
||||
{
|
||||
uint32 slot = threadTotal;
|
||||
threadTotal++;
|
||||
|
||||
uint64 stackBase = (uint64)kmalloc(threadStackSize);
|
||||
uint64 kernelStackTop = (stackBase + threadStackSize) & ~15ull;
|
||||
|
||||
Registers* frame = (Registers*)(kernelStackTop - sizeof(Registers));
|
||||
memset(frame, 0, sizeof(Registers));
|
||||
frame->rip = entry;
|
||||
frame->cs = userCodeSelector | 3;
|
||||
frame->rflags = 0x202;
|
||||
frame->rsp = userStackTop;
|
||||
frame->ss = userDataSelector | 3;
|
||||
|
||||
threads[slot].id = slot;
|
||||
threads[slot].name = name;
|
||||
threads[slot].state = threadRunnable;
|
||||
threads[slot].stackBase = stackBase;
|
||||
threads[slot].kernelStackTop = kernelStackTop;
|
||||
threads[slot].rsp = (uint64)frame;
|
||||
threads[slot].sleepUntil = 0;
|
||||
threads[slot].brk = 0;
|
||||
vfsFdInit(threads[slot].fds);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
uint64 schedule(uint64 currentRsp)
|
||||
{
|
||||
if (!schedulerActive)
|
||||
return currentRsp;
|
||||
|
||||
threads[currentIndex].rsp = currentRsp;
|
||||
if (threads[currentIndex].state == threadRunning)
|
||||
threads[currentIndex].state = threadRunnable;
|
||||
|
||||
uint64 now = pitTicks();
|
||||
for (uint32 i = 0; i < threadTotal; i++)
|
||||
if (threads[i].state == threadSleeping && now >= threads[i].sleepUntil)
|
||||
threads[i].state = threadRunnable;
|
||||
|
||||
uint32 next = 0;
|
||||
for (uint32 step = 1; step <= threadTotal; step++) {
|
||||
uint32 candidate = (currentIndex + step) % threadTotal;
|
||||
if (threads[candidate].state == threadRunnable) {
|
||||
next = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentIndex = next;
|
||||
threads[next].state = threadRunning;
|
||||
tssSetRsp0(threads[next].kernelStackTop);
|
||||
return threads[next].rsp;
|
||||
}
|
||||
|
||||
void schedStart(void)
|
||||
{
|
||||
schedulerActive = true;
|
||||
enableInterrupts();
|
||||
for (;;)
|
||||
halt();
|
||||
}
|
||||
|
||||
void threadExit(uint64 code)
|
||||
{
|
||||
Thread* thread = &threads[currentIndex];
|
||||
thread->state = threadDead;
|
||||
kprintf("[user] pid=%u '%s' exited with code %lu\n", thread->id, thread->name, code);
|
||||
}
|
||||
|
||||
void threadSleep(uint64 milliseconds)
|
||||
{
|
||||
uint64 ticks = milliseconds * pitFrequency() / 1000;
|
||||
if (ticks == 0)
|
||||
ticks = 1;
|
||||
threads[currentIndex].sleepUntil = pitTicks() + ticks;
|
||||
threads[currentIndex].state = threadSleeping;
|
||||
}
|
||||
|
||||
void threadSetBrk(uint32 id, uint64 brk)
|
||||
{
|
||||
threads[id].brk = brk;
|
||||
}
|
||||
|
||||
uint64 currentThreadSbrk(int64 increment)
|
||||
{
|
||||
Thread* thread = &threads[currentIndex];
|
||||
uint64 previous = thread->brk;
|
||||
|
||||
if (increment > 0)
|
||||
pagingMapUserRange(previous, (uint64)increment);
|
||||
|
||||
thread->brk = previous + (uint64)increment;
|
||||
return previous;
|
||||
}
|
||||
|
||||
uint32 threadCount(void)
|
||||
{
|
||||
return threadTotal;
|
||||
}
|
||||
|
||||
Thread* threadAt(uint32 index)
|
||||
{
|
||||
return &threads[index];
|
||||
}
|
||||
|
||||
Thread* currentThread(void)
|
||||
{
|
||||
return &threads[currentIndex];
|
||||
}
|
||||
|
||||
uint32 currentThreadId(void)
|
||||
{
|
||||
return threads[currentIndex].id;
|
||||
}
|
||||
Reference in new issue
Block a user