Scheduler: Creation, destruction and switching of userspace tasks :))
From a TarStream. Not optimal, but OK for the moment.
This commit is contained in:
parent
ea89b92675
commit
a33a72915e
@ -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);
|
||||
auto stack = thread->stack;
|
||||
kinfoln("deleting thread stack @ %#lx, has %zu bytes of stack", stack.bottom(), stack.bytes());
|
||||
// FIXME: Propagate errors I guess?
|
||||
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
|
||||
|
||||
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);
|
||||
|
||||
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())
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user