Luna/kernel/src/thread/Scheduler.cpp

296 lines
8.1 KiB
C++
Raw Normal View History

2022-12-07 15:03:34 +01:00
#include "thread/Scheduler.h"
#include "ELF.h"
2022-12-07 15:03:34 +01:00
#include "Log.h"
#include "arch/CPU.h"
#include "arch/MMU.h"
#include "memory/MemoryManager.h"
#include <luna/Alignment.h>
2022-12-08 14:56:11 +01:00
#include <luna/ScopeGuard.h>
2022-12-07 15:03:34 +01:00
#include <luna/Stack.h>
static Thread g_idle;
static Thread* g_current = nullptr;
static const usize TICKS_PER_TIMESLICE = 20;
namespace Scheduler
{
void init()
{
g_idle.id = 0;
g_idle.init_regs_kernel();
g_idle.set_ip((u64)CPU::idle_loop);
2022-12-07 15:14:58 +01:00
g_idle.state = ThreadState::Idle;
g_idle.is_kernel = true;
2022-12-07 15:03:34 +01:00
g_idle.ticks_left = 1;
// Map some stack for the idle task
2022-12-16 19:44:33 +01:00
u64 idle_stack_vm = MemoryManager::alloc_for_kernel(1, MMU::NoExecute | MMU::ReadWrite)
.expect_value("Error while setting up the idle task, cannot continue");
2022-12-07 15:03:34 +01:00
2022-12-21 20:22:44 +01:00
Stack idle_stack { idle_stack_vm, ARCH_PAGE_SIZE };
2022-12-07 15:03:34 +01:00
g_idle.set_sp(idle_stack.top());
2022-12-18 18:43:17 +01:00
g_idle.stack = idle_stack;
kinfoln("CREATED IDLE THREAD: id %lu with ip %#lx and sp %#lx", g_idle.id, g_idle.ip(), g_idle.sp());
2022-12-07 15:03:34 +01:00
g_current = &g_idle;
}
Thread* current()
{
return g_current;
}
2022-12-07 15:55:58 +01:00
Thread* idle()
{
return &g_idle;
}
2022-12-08 14:56:11 +01:00
Result<void> new_kernel_thread_impl(Thread* thread)
2022-12-07 15:03:34 +01:00
{
2022-12-08 14:56:11 +01:00
// If anything fails, make sure to clean up.
auto guard = make_scope_guard([&] { delete thread; });
2022-12-08 14:56:11 +01:00
2023-01-10 19:31:41 +01:00
const u64 thread_stack_vm = TRY(MemoryManager::alloc_for_kernel(4, MMU::NoExecute | MMU::ReadWrite));
2022-12-08 14:56:11 +01:00
guard.deactivate();
2022-12-08 14:56:11 +01:00
2023-01-10 19:31:41 +01:00
const Stack thread_stack { thread_stack_vm, ARCH_PAGE_SIZE * 4 };
2022-12-07 15:03:34 +01:00
thread->set_sp(thread_stack.top());
2022-12-18 18:43:17 +01:00
thread->stack = thread_stack;
thread->is_kernel = true;
2022-12-07 15:03:34 +01:00
g_threads.append(thread);
kinfoln("CREATED THREAD: id %lu with ip %#lx and sp %#lx", thread->id, thread->ip(), thread->sp());
2022-12-07 15:03:34 +01:00
return {};
}
Result<void> new_kernel_thread(u64 address)
{
2023-01-10 19:31:41 +01:00
Thread* const thread = TRY(new_thread());
2022-12-07 15:03:34 +01:00
thread->init_regs_kernel();
thread->set_ip(address);
2022-12-08 14:56:11 +01:00
return new_kernel_thread_impl(thread);
2022-12-07 15:03:34 +01:00
}
Result<void> new_kernel_thread(void (*func)(void))
{
2023-01-10 19:31:41 +01:00
Thread* const thread = TRY(new_thread());
2022-12-07 15:03:34 +01:00
thread->init_regs_kernel();
thread->set_ip((u64)func);
2022-12-08 14:56:11 +01:00
return new_kernel_thread_impl(thread);
2022-12-07 15:03:34 +01:00
}
Result<void> new_kernel_thread(void (*func)(void*), void* arg)
{
2023-01-10 19:31:41 +01:00
Thread* const thread = TRY(new_thread());
2022-12-07 15:03:34 +01:00
thread->init_regs_kernel();
thread->set_ip((u64)func);
thread->set_arguments((u64)arg, 0, 0, 0);
2022-12-08 14:56:11 +01:00
return new_kernel_thread_impl(thread);
2022-12-07 15:03:34 +01:00
}
static Result<void> create_stacks(Stack& user_stack, Stack& kernel_stack)
{
const u64 THREAD_STACK_BASE = 0x10000;
TRY(MemoryManager::alloc_at(THREAD_STACK_BASE, 4, MMU::ReadWrite | MMU::NoExecute | MMU::User));
auto guard = make_scope_guard([&] { MemoryManager::unmap_owned(THREAD_STACK_BASE, 4); });
2023-01-10 19:31:41 +01:00
const u64 kernel_stack_base = TRY(MemoryManager::alloc_for_kernel(4, MMU::ReadWrite | MMU::NoExecute));
guard.deactivate();
user_stack = { THREAD_STACK_BASE, 4 * ARCH_PAGE_SIZE };
kernel_stack = { kernel_stack_base, 4 * ARCH_PAGE_SIZE };
return {};
}
Result<void> new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream)
{
2023-01-10 19:31:41 +01:00
Thread* const thread = TRY(new_thread());
thread->is_kernel = false;
auto guard = make_scope_guard([&] { delete thread; });
thread->vm_allocator = TRY(UserVM::try_create());
2023-01-10 19:31:41 +01:00
PageDirectory* const directory = TRY(MMU::create_page_directory_for_userspace());
auto directory_guard = make_scope_guard([&] {
MMU::switch_page_directory(MMU::kernel_page_directory());
MemoryManager::free_frame((u64)directory);
});
MMU::switch_page_directory(directory);
thread->init_regs_user();
2023-01-10 19:31:41 +01:00
const ELFData data = TRY(ELFLoader::load(entry, stream));
thread->set_ip(data.entry);
TRY(create_stacks(thread->stack, thread->kernel_stack));
thread->set_sp(thread->stack.top());
thread->directory = directory;
guard.deactivate();
directory_guard.deactivate();
kinfoln("CREATED USERSPACE THREAD: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(),
thread->sp(), thread->kernel_stack.top());
g_threads.append(thread);
return {};
}
2022-12-19 12:24:15 +01:00
void reap_thread(Thread* thread)
{
kinfoln("reap: reaping thread with id %zu", thread->id);
if (thread->is_kernel)
{
auto stack = thread->stack;
// FIXME: Propagate errors I guess?
kinfoln("deleting stack @ %#lx", stack.bottom());
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
}
else
{
auto stack = thread->kernel_stack;
kinfoln("deleting kstack @ %#lx", stack.bottom());
// FIXME: Propagate errors I guess?
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
}
if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory);
2022-12-19 12:24:15 +01:00
delete thread;
}
2022-12-07 15:03:34 +01:00
Thread* pick_task()
{
Thread* old = g_current;
2022-12-07 15:14:58 +01:00
if (old->is_idle())
2022-12-07 15:03:34 +01:00
{
2022-12-07 15:17:20 +01:00
auto maybe_last = g_threads.last();
if (!maybe_last.has_value()) // No threads!!
2022-12-07 15:03:34 +01:00
return &g_idle;
2022-12-07 15:17:20 +01:00
g_current = old = maybe_last.value();
2022-12-07 15:03:34 +01:00
}
2022-12-07 15:17:20 +01:00
bool has_found_thread = false;
2022-12-07 15:03:34 +01:00
do {
auto maybe_next = g_threads.next(g_current);
if (!maybe_next.has_value()) g_current = g_threads.expect_first();
2022-12-07 15:03:34 +01:00
else
g_current = maybe_next.value();
2022-12-07 15:17:20 +01:00
if (g_current->state == ThreadState::Runnable)
{
has_found_thread = true;
2022-12-07 15:03:34 +01:00
break;
2022-12-07 15:17:20 +01:00
}
2022-12-07 15:03:34 +01:00
} while (g_current != old);
2022-12-07 15:17:20 +01:00
if (!has_found_thread) g_current = &g_idle;
2022-12-07 15:03:34 +01:00
return g_current;
}
void generic_switch_context(Thread* old_thread, Thread* new_thread, Registers* regs)
{
if (old_thread != new_thread)
{
switch_context(old_thread, new_thread, regs);
if (!new_thread->is_kernel)
{
MMU::switch_page_directory(new_thread->directory);
CPU::switch_kernel_stack(new_thread->kernel_stack.top());
}
}
2022-12-07 15:03:34 +01:00
2022-12-07 15:14:58 +01:00
if (new_thread->is_idle())
2022-12-07 15:03:34 +01:00
{
new_thread->ticks_left = 1; // The idle task only runs for 1 tick so we can check for new runnable tasks
// as fast as possible.
}
else
new_thread->ticks_left = TICKS_PER_TIMESLICE;
}
void switch_task(Registers* regs)
{
Thread* old_thread = g_current;
Thread* new_thread = pick_task();
generic_switch_context(old_thread, new_thread, regs);
}
void invoke(Registers* regs)
{
CPU::disable_interrupts();
g_current->ticks++;
if (is_in_kernel(regs)) g_current->ticks_in_kernel++;
else
g_current->ticks_in_user++;
g_current->ticks_left--;
2022-12-07 15:55:58 +01:00
g_threads.for_each([](Thread* thread) {
if (thread->state == ThreadState::Sleeping)
{
if (--thread->sleep_ticks_left == 0) thread->state = ThreadState::Runnable;
}
});
2022-12-07 15:03:34 +01:00
if (!g_current->ticks_left) switch_task(regs);
}
2022-12-19 12:43:23 +01:00
LinkedList<Thread> check_for_dying_threads()
{
2022-12-19 12:43:23 +01:00
LinkedList<Thread> result;
g_threads.delayed_for_each([&](Thread* thread) {
if (thread->state == ThreadState::Dying)
{
g_threads.remove(thread);
result.append(thread);
}
});
return result;
}
2022-12-07 15:55:58 +01:00
}
void kernel_sleep(u64 ms)
{
g_current->sleep_ticks_left = ms;
g_current->state = ThreadState::Sleeping;
kernel_yield();
}
[[noreturn]] void kernel_exit()
{
g_current->state = ThreadState::Dying;
kernel_yield();
unreachable();
2023-01-02 13:07:29 +01:00
}