diff --git a/kernel/kernel/PIT.cpp b/kernel/kernel/PIT.cpp index 3aaa704c..fce8c2b3 100644 --- a/kernel/kernel/PIT.cpp +++ b/kernel/kernel/PIT.cpp @@ -24,11 +24,11 @@ namespace PIT { - static uint64_t s_system_time = 0; + static volatile uint64_t s_system_time = 0; void irq_handler() { - s_system_time++; + s_system_time = s_system_time + 1; Kernel::Scheduler::get().reschedule(); } @@ -55,7 +55,10 @@ namespace PIT { if (ms == 0) return; - Kernel::Scheduler::get().set_current_thread_sleeping(ms); + uint64_t wake_time = s_system_time + ms; + Kernel::Scheduler::get().set_current_thread_sleeping(wake_time); + if (s_system_time < wake_time) + dwarnln("sleep woke {} ms too soon", wake_time - s_system_time); } } diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 850743ab..0c805517 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -54,9 +54,9 @@ namespace Kernel ASSERT_NOT_REACHED(); } - BAN::RefCounted Scheduler::current_thread() + Thread& Scheduler::current_thread() { - return m_current_thread ? m_current_thread->thread : m_idle_thread; + return m_current_thread ? *m_current_thread->thread : *m_idle_thread; } void Scheduler::reschedule() @@ -68,13 +68,11 @@ namespace Kernel return; m_last_reschedule = PIT::ms_since_boot(); - if (!m_sleeping_threads.empty()) - m_sleeping_threads.front().wake_delta--; wake_threads(); if (save_current_thread()) return; - get_next_thread(); + advance_current_thread(); execute_current_thread(); ASSERT_NOT_REACHED(); } @@ -83,7 +81,8 @@ namespace Kernel { VERIFY_CLI(); - while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_delta == 0) + uint64_t current_time = PIT::ms_since_boot(); + while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time) { auto thread = m_sleeping_threads.front().thread; m_sleeping_threads.remove(m_sleeping_threads.begin()); @@ -109,7 +108,7 @@ namespace Kernel return {}; } - void Scheduler::get_next_thread() + void Scheduler::advance_current_thread() { VERIFY_CLI(); @@ -118,11 +117,29 @@ namespace Kernel m_current_thread = {}; return; } - if (!m_current_thread || ++m_current_thread == m_active_threads.end()) m_current_thread = m_active_threads.begin(); } + void Scheduler::remove_and_advance_current_thread() + { + VERIFY_CLI(); + + ASSERT(m_current_thread); + + if (m_active_threads.size() == 1) + { + m_active_threads.remove(m_current_thread); + m_current_thread = {}; + } + else + { + auto temp = m_current_thread; + advance_current_thread(); + m_active_threads.remove(temp); + } + } + // NOTE: this is declared always inline, so we don't corrupt the stack // after getting the rsp ALWAYS_INLINE bool Scheduler::save_current_thread() @@ -138,75 +155,67 @@ namespace Kernel } read_rsp(rsp); - auto current = current_thread(); - current->set_rip(rip); - current->set_rsp(rsp); + auto& current = current_thread(); + current.set_rip(rip); + current.set_rsp(rsp); return false; } void Scheduler::execute_current_thread() { VERIFY_CLI(); + + auto& current = current_thread(); - auto current = current_thread(); - - if (current->started()) + if (current.started()) { - continue_thread(current->rsp(), current->rip()); + continue_thread(current.rsp(), current.rip()); } else { - current->set_started(); - start_thread(current->function(), current->rsp(), current->rip()); + current.set_started(); + start_thread(current.function(), current.rsp(), current.rip()); } ASSERT_NOT_REACHED(); } - void Scheduler::set_current_thread_sleeping(uint64_t wake_delta) +#pragma GCC push_options +#pragma GCC optimize("O0") + void Scheduler::set_current_thread_sleeping(uint64_t wake_time) { DISABLE_INTERRUPTS(); ASSERT(m_current_thread); - auto current = m_current_thread->thread; + auto sleeping = m_current_thread->thread; - auto temp = m_current_thread; if (save_current_thread()) return; - get_next_thread(); - m_active_threads.remove(temp); + remove_and_advance_current_thread(); auto it = m_sleeping_threads.begin(); - for (; it != m_sleeping_threads.end(); it++) - { - if (wake_delta <= it->wake_delta) + if (wake_time <= it->wake_time) break; - wake_delta -= it->wake_delta; - } - - if (it != m_sleeping_threads.end()) - it->wake_delta -= wake_delta; // This should work as we released enough memory from active thread static_assert(sizeof(ActiveThread) == sizeof(SleepingThread)); - MUST(m_sleeping_threads.insert(it, { current, wake_delta })); + MUST(m_sleeping_threads.emplace(it, sleeping, wake_time)); + sleeping.clear(); execute_current_thread(); ASSERT_NOT_REACHED(); } +#pragma GCC pop_options void Scheduler::set_current_thread_done() { DISABLE_INTERRUPTS(); ASSERT(m_current_thread); + remove_and_advance_current_thread(); - auto temp = m_current_thread; - get_next_thread(); - m_active_threads.remove(temp); - execute_current_thread(); ASSERT_NOT_REACHED(); } diff --git a/kernel/kernel/Shell.cpp b/kernel/kernel/Shell.cpp index 30e2ca53..1c3d9e87 100644 --- a/kernel/kernel/Shell.cpp +++ b/kernel/kernel/Shell.cpp @@ -59,8 +59,7 @@ namespace Kernel TTY_PRINT("{}", m_prompt); for (;;) { - //PIT::sleep(1); // sleep until next reschedule - asm volatile("hlt"); + PIT::sleep(1); // sleep until next reschedule Input::update(); } }