From 1bd8b0fe5ce8ce5384e466f61f8dd4f7547d7964 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 19 Feb 2023 17:53:29 +0200 Subject: [PATCH] Kernel: Sleep now actually sleeps and allows idling --- kernel/arch/i386/IDT.cpp | 4 +- kernel/arch/i386/Thread.S | 12 ++-- kernel/arch/x86_64/IDT.cpp | 4 +- kernel/arch/x86_64/Thread.S | 12 ++-- kernel/include/kernel/Scheduler.h | 14 ++-- kernel/include/kernel/Thread.h | 4 +- kernel/kernel/PIT.cpp | 4 +- kernel/kernel/Scheduler.cpp | 104 ++++++++++++++++++------------ kernel/kernel/Thread.cpp | 11 ++-- kernel/kernel/kernel.cpp | 4 +- 10 files changed, 101 insertions(+), 72 deletions(-) diff --git a/kernel/arch/i386/IDT.cpp b/kernel/arch/i386/IDT.cpp index 23045380..6908a421 100644 --- a/kernel/arch/i386/IDT.cpp +++ b/kernel/arch/i386/IDT.cpp @@ -129,7 +129,9 @@ found: else dprintln("no handler for irq 0x{2H}\n", irq); - InterruptController::get().eoi(irq); + // NOTE: Scheduler sends PIT eoi's + if (irq != PIT_IRQ) + InterruptController::get().eoi(irq); } extern "C" void handle_irq_common(); diff --git a/kernel/arch/i386/Thread.S b/kernel/arch/i386/Thread.S index ab553874..934d41c3 100644 --- a/kernel/arch/i386/Thread.S +++ b/kernel/arch/i386/Thread.S @@ -11,12 +11,11 @@ exit_thread_trampoline: pushl %eax ret -# void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rbp, uint32_t rip) +# void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rip) .global start_thread start_thread: movl %esp, %eax - movl 28(%eax), %ecx - movl 24(%eax), %ebp + movl 24(%eax), %ecx movl 20(%eax), %esp pushl 16(%eax) @@ -25,14 +24,15 @@ start_thread: pushl 4(%eax) pushl $exit_thread_trampoline + movl $0, %ebp + sti jmp *%ecx -# void continue_thread(uint32_t rsp, uint32_t rbp, uint32_t rip) +# void continue_thread(uint32_t rsp, uint32_t rip) .global continue_thread continue_thread: - movl 12(%esp), %ecx - movl 8(%esp), %ebp + movl 8(%esp), %ecx movl 4(%esp), %esp movl $0, %eax jmp *%ecx \ No newline at end of file diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index 764e67d7..5c035dd2 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -126,7 +126,9 @@ namespace IDT dprintln("no handler for irq 0x{2H}\n", irq); } - InterruptController::get().eoi(irq); + // NOTE: Scheduler sends PIT eoi's + if (irq != PIT_IRQ) + InterruptController::get().eoi(irq); } static void flush_idt() diff --git a/kernel/arch/x86_64/Thread.S b/kernel/arch/x86_64/Thread.S index 9d375ba0..51bdb0ef 100644 --- a/kernel/arch/x86_64/Thread.S +++ b/kernel/arch/x86_64/Thread.S @@ -8,20 +8,18 @@ exit_thread_trampoline: movq 8(%rsp), %rdi ret -# void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rbp, uint64_t rip) +# void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rip) .global start_thread start_thread: - movq 8(%rsp), %rcx movq %r8, %rsp - movq %r9, %rbp + movq $0, %rbp pushq $exit_thread_trampoline sti - jmp *%rcx + jmp *%r9 -# void continue_thread(uint64_t rsp, uint64_t rbp, uint64_t rip) +# void continue_thread(uint64_t rsp, uint64_t rip) .global continue_thread continue_thread: movq %rdi, %rsp - movq %rsi, %rbp movq $0, %rax - jmp *%rdx \ No newline at end of file + jmp *%rsi \ No newline at end of file diff --git a/kernel/include/kernel/Scheduler.h b/kernel/include/kernel/Scheduler.h index ecd0fffd..a0b5957c 100644 --- a/kernel/include/kernel/Scheduler.h +++ b/kernel/include/kernel/Scheduler.h @@ -19,27 +19,33 @@ namespace Kernel const Thread& current_thread() const; template - void add_thread(const BAN::Function& func, Args... args) + [[nodiscard]] BAN::ErrorOr add_thread(const BAN::Function& func, Args... args) { uintptr_t flags; asm volatile("pushf; pop %0" : "=r"(flags)); asm volatile("cli"); - MUST(m_threads.emplace_back(func, BAN::forward(args)...)); + TRY(m_threads.emplace_back(func, BAN::forward(args)...)); if (flags & (1 << 9)) asm volatile("sti"); + return {}; } - void switch_thread(); + void reschedule(); + void set_current_thread_sleeping(); void start(); - static constexpr size_t ms_between_switch = 1; + static constexpr size_t ms_between_switch = 4; private: Scheduler() {} + void switch_thread(); private: BAN::LinkedList m_threads; BAN::LinkedList::iterator m_current_iterator; + uint64_t m_last_reschedule = 0; + + friend class Thread; }; } \ No newline at end of file diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index e3f5e109..3518033a 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -17,6 +17,7 @@ namespace Kernel NotStarted, Running, Paused, + Sleeping, Done, }; @@ -36,11 +37,9 @@ namespace Kernel uint32_t id() const { return m_id; } void set_rsp(uintptr_t rsp) { m_rsp = rsp; } - void set_rbp(uintptr_t rbp) { m_rbp = rbp; } void set_rip(uintptr_t rip) { m_rip = rip; } void set_state(State state) { m_state = state; } uintptr_t rsp() const { return m_rsp; } - uintptr_t rbp() const { return m_rbp; } uintptr_t rip() const { return m_rip; } State state() const { return m_state; } @@ -55,7 +54,6 @@ namespace Kernel State m_state = State::NotStarted; uintptr_t m_args[4] = {}; uintptr_t m_rip = 0; - uintptr_t m_rbp = 0; uintptr_t m_rsp = 0; const uint32_t m_id = 0; diff --git a/kernel/kernel/PIT.cpp b/kernel/kernel/PIT.cpp index cf20b9df..74c8738f 100644 --- a/kernel/kernel/PIT.cpp +++ b/kernel/kernel/PIT.cpp @@ -28,7 +28,7 @@ namespace PIT void irq_handler() { s_system_time++; - Kernel::Scheduler::get().switch_thread(); + Kernel::Scheduler::get().reschedule(); } uint64_t ms_since_boot() @@ -54,7 +54,7 @@ namespace PIT { uint64_t end = s_system_time + ms; while (s_system_time < end) - asm volatile("hlt"); + Kernel::Scheduler::get().set_current_thread_sleeping(); } } diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index e45a7ee0..f10dd211 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -7,14 +7,16 @@ namespace Kernel static Scheduler* s_instance = nullptr; - extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rbp, uintptr_t rip); - extern "C" void continue_thread(uintptr_t rsp, uintptr_t rbp, uintptr_t rip); + extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rip); + extern "C" void continue_thread(uintptr_t rsp, uintptr_t rip); extern "C" uintptr_t read_rip(); void Scheduler::initialize() { ASSERT(!s_instance); s_instance = new Scheduler(); + ASSERT(s_instance); + MUST(s_instance->add_thread(BAN::Function([] { for(;;) asm volatile("hlt"); }))); } Scheduler& Scheduler::get() @@ -28,72 +30,92 @@ namespace Kernel return *m_current_iterator; } + void Scheduler::reschedule() + { + ASSERT(InterruptController::get().is_in_service(PIT_IRQ)); + InterruptController::get().eoi(PIT_IRQ); + + uint64_t current_time = PIT::ms_since_boot(); + if (m_last_reschedule + ms_between_switch > current_time) + return; + m_last_reschedule = current_time; + + for (Thread& thread : m_threads) + if (thread.state() == Thread::State::Sleeping) + thread.set_state(Thread::State::Paused); + + switch_thread(); + } + void Scheduler::switch_thread() { - uintptr_t rsp, rbp, rip; + uintptr_t rsp, rip; + push_callee_saved(); if (!(rip = read_rip())) + { + pop_callee_saved(); return; + } read_rsp(rsp); - read_rbp(rbp); - - static uint8_t cnt = 0; - if (cnt++ % ms_between_switch) - return; - - ASSERT(InterruptController::get().is_in_service(PIT_IRQ)); - - ASSERT(m_threads.size() > 0); - if (m_threads.size() == 1) - return; - - ASSERT(m_current_iterator); - - auto next_iterator = m_current_iterator; - if (++next_iterator == m_threads.end()) - next_iterator = m_threads.begin(); + ASSERT(m_threads.size() > 1); + Thread& current = *m_current_iterator; - Thread& next = *next_iterator; - ASSERT(next.state() == Thread::State::Paused || next.state() == Thread::State::NotStarted); + //if (m_threads.size() == 2 && current.id() != 0 && current.state() == Thread::State::Running) + // return; if (current.state() == Thread::State::Done) { - // NOTE: this does not invalidate the next/next_iterator - // since we are working with linked list m_threads.remove(m_current_iterator); - m_current_iterator = decltype(m_threads)::iterator(); + m_current_iterator = m_threads.begin(); } - - if (m_current_iterator) + else { current.set_rsp(rsp); - current.set_rbp(rbp); current.set_rip(rip); - current.set_state(Thread::State::Paused); + if (current.state() != Thread::State::Sleeping) + current.set_state(Thread::State::Paused); } + auto next_iterator = m_current_iterator; + if (++next_iterator == m_threads.end()) + next_iterator = ++m_threads.begin(); + if (next_iterator->state() == Thread::State::Sleeping) + next_iterator = m_threads.begin(); + Thread& next = *next_iterator; + m_current_iterator = next_iterator; - if (next.state() == Thread::State::NotStarted) + switch (next.state()) { - InterruptController::get().eoi(PIT_IRQ); - next.set_state(Thread::State::Running); - const uintptr_t* args = next.args(); - start_thread(args[0], args[1], args[2], args[3], next.rsp(), next.rbp(), next.rip()); - } - else if (next.state() == Thread::State::Paused) - { - next.set_state(Thread::State::Running); - continue_thread(next.rsp(), next.rbp(), next.rip()); + case Thread::State::NotStarted: + next.set_state(Thread::State::Running); + start_thread(next.args()[0], next.args()[1], next.args()[2], next.args()[3], next.rsp(), next.rip()); + break; + case Thread::State::Paused: + next.set_state(Thread::State::Running); + continue_thread(next.rsp(), next.rip()); + break; + case Thread::State::Sleeping: ASSERT(false); + case Thread::State::Running: ASSERT(false); + case Thread::State::Done: ASSERT(false); } ASSERT(false); } + + void Scheduler::set_current_thread_sleeping() + { + asm volatile("cli"); + m_current_iterator->set_state(Thread::State::Sleeping); + switch_thread(); + asm volatile("sti"); + } void Scheduler::start() { - ASSERT(m_threads.size() > 0); + ASSERT(m_threads.size() > 1); m_current_iterator = m_threads.begin(); @@ -102,7 +124,7 @@ namespace Kernel current.set_state(Thread::State::Running); const uintptr_t* args = current.args(); - start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rbp(), current.rip()); + start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rip()); ASSERT(false); } diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 8ed19fb6..b7fa686d 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -10,9 +10,9 @@ namespace Kernel { - static uint32_t s_next_id = 1; + static uint32_t s_next_id = 0; - static constexpr size_t thread_stack_size = PAGE_SIZE; + static constexpr size_t thread_stack_size = 16384; template static void write_to_stack(uintptr_t& rsp, const T& value) @@ -27,8 +27,7 @@ namespace Kernel m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE); ASSERT(m_stack_base); - m_rbp = (uintptr_t)m_stack_base + thread_stack_size; - m_rsp = m_rbp; + m_rsp = (uintptr_t)m_stack_base + thread_stack_size; m_rip = rip; m_args[1] = arg1; m_args[2] = arg2; @@ -54,8 +53,10 @@ namespace Kernel void Thread::on_exit() { + asm volatile("cli"); m_state = State::Done; - for (;;) asm volatile("hlt"); + Scheduler::get().switch_thread(); + ASSERT(false); } } \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index d2dbe5d4..064716d2 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -97,8 +97,8 @@ extern "C" void kernel_main() Scheduler::initialize(); Scheduler& scheduler = Scheduler::get(); - scheduler.add_thread(BAN::Function([] { DiskIO::initialize(); })); - scheduler.add_thread(BAN::Function([tty1] { Shell(tty1).run(); })); + MUST(scheduler.add_thread(BAN::Function([] { DiskIO::initialize(); }))); + MUST(scheduler.add_thread(BAN::Function([tty1] { Shell(tty1).run(); }))); scheduler.start(); ASSERT(false); } \ No newline at end of file