-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kernel: implement a basic cooperative scheduler for now
- Loading branch information
Showing
7 changed files
with
172 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#include <kernel/intrinsics.hpp> | ||
#include <kernel/log.hpp> | ||
#include <kernel/memory/allocator.hpp> | ||
#include <kernel/screen/framebuffer.hpp> | ||
#include <kernel/tasks/scheduler.hpp> | ||
|
||
using namespace kernel::tasks; | ||
|
||
bool initialized = false; | ||
|
||
bool Scheduler::initialized() { | ||
return ::initialized; | ||
} | ||
|
||
Scheduler& Scheduler::get() { | ||
DisableInterruptsGuard guard; | ||
static Scheduler instance; | ||
return instance; | ||
} | ||
|
||
void kernel::tasks::yield_thread() { | ||
asm volatile("int %0;" : : "i"(SYSCALL_INTERRUPT_N)); | ||
} | ||
|
||
void thread1_func() { | ||
while (true) { | ||
// kdbgln("hello from thread 1"); | ||
yield_thread(); | ||
} | ||
halt(false); | ||
} | ||
|
||
void thread2_func() { | ||
while (true) { | ||
// kdbgln("hello from thread 2"); | ||
yield_thread(); | ||
} | ||
halt(false); | ||
} | ||
|
||
void thread3_func() { | ||
kernel::framebuffer::loop(); | ||
} | ||
|
||
Thread create_thread(usize stack_pages, void (*function)()) { | ||
Thread thread; | ||
thread.stack = kernel::alloc::allocate_pages(stack_pages); | ||
thread.state.rsp = | ||
reinterpret_cast<uptr>(thread.stack) + kernel::PAGE_SIZE * stack_pages - sizeof(uptr); | ||
*reinterpret_cast<uptr*>(thread.state.rsp) = 0; | ||
thread.state.rip = reinterpret_cast<uptr>(function); | ||
thread.state.cs = 0; | ||
kdbgln("thread rsp={:#x}", thread.state.rsp); | ||
return thread; | ||
} | ||
|
||
void Scheduler::init() { | ||
m_threads.push(create_thread(1, &thread1_func)); | ||
m_threads.push(create_thread(1, &thread2_func)); | ||
m_threads.push(create_thread(3, &thread3_func)); | ||
::initialized = true; | ||
yield_thread(); // jump into the scheduler interrupt | ||
} | ||
|
||
kernel::interrupt::Registers kernel_init_state; | ||
|
||
void Scheduler::handle_interrupt(interrupt::Registers* regs) { | ||
if (kernel_init_state.rip == 0) { | ||
kernel_init_state = *regs; | ||
} | ||
|
||
if (m_threads.empty()) return; | ||
|
||
if (!m_threads[m_active_idx].first_time) { | ||
m_threads[m_active_idx].state = *regs; | ||
} | ||
const auto next_index = (m_active_idx + 1) % m_threads.size(); | ||
auto& next_thread = m_threads[next_index]; | ||
// silly | ||
if (next_thread.first_time) { | ||
next_thread.state.cs = kernel_init_state.cs; | ||
next_thread.state.rflags = 0b1000000000; // interrupt enable flag | ||
next_thread.first_time = false; | ||
} | ||
*regs = next_thread.state; | ||
m_active_idx = next_index; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#pragma once | ||
|
||
#include <kernel/idt.hpp> | ||
#include <stl/types.hpp> | ||
#include <stl/vector.hpp> | ||
|
||
namespace kernel::tasks { | ||
|
||
static constexpr u8 SYSCALL_INTERRUPT_N = 0x80; | ||
|
||
void yield_thread(); | ||
|
||
struct Thread { | ||
interrupt::Registers state; | ||
void* stack = nullptr; | ||
bool first_time = true; | ||
}; | ||
|
||
class Scheduler { | ||
Vector<Thread> m_threads; | ||
usize m_active_idx = 0; | ||
|
||
public: | ||
static Scheduler& get(); | ||
static bool initialized(); | ||
|
||
void init(); | ||
|
||
void handle_interrupt(interrupt::Registers* regs); | ||
}; | ||
|
||
} |