diff --git a/kernel/include/kernel/Scheduler.h b/kernel/include/kernel/Scheduler.h index 9c8f35e7..897b240e 100644 --- a/kernel/include/kernel/Scheduler.h +++ b/kernel/include/kernel/Scheduler.h @@ -58,7 +58,7 @@ namespace Kernel BAN::ErrorOr initialize(); void reschedule(YieldRegisters*); - void reschedule_if_idle(); + void reschedule_if_needed(); void on_timer_interrupt(); void on_yield(YieldRegisters*); @@ -118,6 +118,8 @@ namespace Kernel bool m_should_calculate_max_load_threads { true }; + bool m_has_pending_reschedule { false }; + Thread* m_idle_thread { nullptr }; friend class ThreadBlocker; diff --git a/kernel/kernel/IDT.cpp b/kernel/kernel/IDT.cpp index 3799186a..de1d17e3 100644 --- a/kernel/kernel/IDT.cpp +++ b/kernel/kernel/IDT.cpp @@ -413,10 +413,14 @@ namespace Kernel extern "C" void cpp_ipi_handler() { - ASSERT(InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE)); - InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE); + if (!InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE)) + return; + Processor::handle_ipi(); - Processor::scheduler().reschedule_if_idle(); + + InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE); + + Processor::scheduler().reschedule_if_needed(); } extern "C" void cpp_timer_handler() @@ -429,13 +433,17 @@ namespace Kernel asm volatile("cli; 1: hlt; jmp 1b"); } - ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE)); - InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE); + if (!InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE)) + return; if (Processor::current_is_bsp()) Process::update_alarm_queue(); Processor::scheduler().on_timer_interrupt(); + + InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE); + + Processor::scheduler().reschedule_if_needed(); } extern "C" void cpp_irq_handler(uint32_t irq) @@ -453,15 +461,14 @@ namespace Kernel if (!InterruptController::get().is_in_service(irq)) return; - InterruptController::get().eoi(irq); if (auto* handler = s_interruptables[irq]) handler->handle_irq(); else dprintln("no handler for irq 0x{2H}", irq); - Processor::scheduler().reschedule_if_idle(); + InterruptController::get().eoi(irq); - ASSERT(Thread::current().state() != Thread::State::Terminated); + Processor::scheduler().reschedule_if_needed(); } extern "C" void cpp_check_signal() diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 6edb5d5a..6611cef7 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -332,12 +332,15 @@ namespace Kernel static_cast(interrupt_controller).set_timer_dealine(deadline_ns); } - void Scheduler::reschedule_if_idle() + void Scheduler::reschedule_if_needed() { ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled); - if (m_current == nullptr && !m_run_queue.empty()) + if ((is_idle() && !m_run_queue.empty()) || m_has_pending_reschedule) + { + m_has_pending_reschedule = false; Processor::yield(); + } } extern "C" void scheduler_on_yield_trampoline(YieldRegisters* yield_registers) @@ -366,7 +369,7 @@ namespace Kernel // NOTE: yield will update the timer deadline, but if we do not yield make sure // we set the next deadline or we won't get another timer interrupt if (is_idle() || SystemTimer::get().ns_since_boot() >= m_next_reschedule_ns) - Processor::yield(); + m_has_pending_reschedule = true; else update_wake_up_deadline(); }