diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 7592b85f..a9ebfe4e 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -35,7 +35,36 @@ void heap_thread() CPU::disable_interrupts(); dump_heap_usage(); kdbgln("Kernel uses %lu vm pages", KernelVM::used() / ARCH_PAGE_SIZE); - while (true) kernel_sleep(UINT64_MAX); + kernel_exit(); +} + +void reap_thread() +{ + while (true) + { + CPU::disable_interrupts(); + auto dying_threads = Scheduler::check_for_dying_threads(); + CPU::enable_interrupts(); + + if (dying_threads.count()) + { + Thread* thread_to_reap = dying_threads.expect_first(); + Thread* next_thread = thread_to_reap; + + while (thread_to_reap) + { + next_thread = dying_threads.next(thread_to_reap).value_or(nullptr); + kinfoln("reap: reaping thread with id %zu", thread_to_reap->id); + auto stack = thread_to_reap->stack; + kinfoln("deleting thread stack @ %#lx, has %zu bytes of stack", stack.bottom(), stack.bytes()); + MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); + delete thread_to_reap; + thread_to_reap = next_thread; + } + } + + kernel_sleep(250); + } } Result init() @@ -67,6 +96,7 @@ Result init() TRY(Scheduler::new_kernel_thread(async_thread)); TRY(Scheduler::new_kernel_thread(heap_thread)); + TRY(Scheduler::new_kernel_thread(reap_thread)); CPU::platform_finish_init(); diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index bba4f6d9..fc43f6c1 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -167,6 +167,32 @@ namespace Scheduler if (!g_current->ticks_left) switch_task(regs); } + + DoublyLinkedList check_for_dying_threads() + { + DoublyLinkedList result; + + Thread* thread_to_remove = nullptr; + + g_threads.for_each([&](Thread* thread) { + if (thread_to_remove) + { + g_threads.remove(thread_to_remove); + result.append(thread_to_remove); + } + + if (thread->state == ThreadState::Dying) { thread_to_remove = thread; } + else { thread_to_remove = nullptr; } + }); + + if (thread_to_remove) + { + g_threads.remove(thread_to_remove); + result.append(thread_to_remove); + } + + return result; + } } void kernel_sleep(u64 ms) @@ -174,4 +200,11 @@ 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(); } \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.h b/kernel/src/thread/Scheduler.h index 57bb85ad..e0f71973 100644 --- a/kernel/src/thread/Scheduler.h +++ b/kernel/src/thread/Scheduler.h @@ -17,7 +17,10 @@ namespace Scheduler void switch_task(Registers* regs); void invoke(Registers* regs); + + DoublyLinkedList check_for_dying_threads(); } extern "C" void kernel_yield(); -void kernel_sleep(u64 ms); \ No newline at end of file +void kernel_sleep(u64 ms); +[[noreturn]] void kernel_exit(); \ No newline at end of file diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 43d40007..aac36c41 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -14,7 +14,8 @@ enum class ThreadState { Idle, Runnable, - Sleeping + Sleeping, + Dying }; struct Thread : public DoublyLinkedListNode