Scheduler: Creation, destruction and switching of userspace tasks :))

From a TarStream. Not optimal, but OK for the moment.
This commit is contained in:
apio 2023-01-05 21:52:26 +01:00
parent ea89b92675
commit a33a72915e
Signed by: apio
GPG Key ID: B8A7D06E42258954
2 changed files with 91 additions and 5 deletions

View File

@ -1,4 +1,5 @@
#include "thread/Scheduler.h"
#include "ELF.h"
#include "Log.h"
#include "arch/CPU.h"
#include "arch/MMU.h"
@ -19,6 +20,7 @@ namespace Scheduler
g_idle.init_regs_kernel();
g_idle.set_ip((u64)CPU::idle_loop);
g_idle.state = ThreadState::Idle;
g_idle.is_kernel = true;
g_idle.ticks_left = 1;
@ -60,6 +62,8 @@ namespace Scheduler
thread->stack = thread_stack;
thread->is_kernel = true;
g_threads.append(thread);
kinfoln("CREATED THREAD: id %lu with ip %lx and sp %lx", thread->id, thread->ip(), thread->sp());
@ -95,13 +99,84 @@ namespace Scheduler
return new_kernel_thread_impl(thread);
}
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); });
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)
{
Thread* thread = TRY(new_thread());
thread->is_kernel = false;
auto guard = make_scope_guard([&] { delete thread; });
auto 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();
auto 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 %lx and sp %lx (ksp %lx)", thread->id, thread->ip(),
thread->sp(), thread->kernel_stack.top());
g_threads.append(thread);
return {};
}
void reap_thread(Thread* thread)
{
kinfoln("reap: reaping thread with id %zu", thread->id);
if (thread->is_kernel)
{
auto stack = thread->stack;
kinfoln("deleting thread stack @ %#lx, has %zu bytes of stack", stack.bottom(), stack.bytes());
// 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);
delete thread;
}
@ -138,7 +213,15 @@ namespace Scheduler
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 (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());
}
}
if (new_thread->is_idle())
{

View File

@ -1,5 +1,6 @@
#pragma once
#include "thread/Thread.h"
#include <luna/TarStream.h>
namespace Scheduler
{
@ -12,6 +13,8 @@ namespace Scheduler
Result<void> new_kernel_thread(void (*func)(void));
Result<void> new_kernel_thread(void (*func)(void*), void* arg);
Result<void> new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream);
Thread* pick_task();
void reap_thread(Thread* thread);