From 342f7a6b0fe625d9d9920bd80659dd8f3e693578 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 19 Jul 2019 17:21:13 +0200 Subject: [PATCH] Move runnable/non-runnable list control entirely over to Scheduler This way, we can change how the scheduler works without having to change Thread too. --- Kernel/Scheduler.cpp | 64 ++++++++++++++++++++++++++++++++++++++-- Kernel/Scheduler.h | 25 ++++++++++++++++ Kernel/Thread.cpp | 18 ++---------- Kernel/Thread.h | 70 ++++++++------------------------------------ 4 files changed, 102 insertions(+), 75 deletions(-) diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index e361ec6effb..10b1f899f81 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -6,6 +6,65 @@ #include #include +struct SchedulerData { + typedef IntrusiveList ThreadList; + + ThreadList m_runnable_threads; + ThreadList m_nonrunnable_threads; + + ThreadList& thread_list_for_state(Thread::State state) + { + if (Thread::is_runnable_state(state)) + return m_runnable_threads; + return m_nonrunnable_threads; + } +}; + +static SchedulerData* g_scheduler_data; + +void Scheduler::init_thread(Thread& thread) +{ + g_scheduler_data->m_nonrunnable_threads.append(thread); +} + +void Scheduler::update_state_for_thread(Thread& thread) +{ + auto& list = g_scheduler_data->thread_list_for_state(thread.state()); + + if (list.contains(thread)) + return; + + list.append(thread); +} + +IterationDecision Scheduler::for_each_runnable_func(Function&& callback) +{ + ASSERT_INTERRUPTS_DISABLED(); + auto& tl = g_scheduler_data->m_runnable_threads; + for (auto it = tl.begin(); it != tl.end();) { + auto thread = *it; + it = ++it; + if (callback(*thread) == IterationDecision::Break) + return IterationDecision::Break; + } + + return IterationDecision::Continue; +} + +IterationDecision Scheduler::for_each_nonrunnable_func(Function&& callback) +{ + ASSERT_INTERRUPTS_DISABLED(); + auto& tl = g_scheduler_data->m_nonrunnable_threads; + for (auto it = tl.begin(); it != tl.end();) { + auto thread = *it; + it = ++it; + if (callback(*thread) == IterationDecision::Break) + return IterationDecision::Break; + } + + return IterationDecision::Continue; +} + //#define LOG_EVERY_CONTEXT_SWITCH //#define SCHEDULER_DEBUG //#define SCHEDULER_RUNNABLE_DEBUG @@ -261,7 +320,7 @@ bool Scheduler::pick_next() auto now_usec = now.tv_usec; // Check and unblock threads whose wait conditions have been met. - Thread::for_each_nonrunnable([&](Thread& thread) { + Scheduler::for_each_nonrunnable([&](Thread& thread) { thread.consider_unblock(now_sec, now_usec); return IterationDecision::Continue; }); @@ -330,7 +389,7 @@ bool Scheduler::pick_next() }); #endif - auto& runnable_list = *Thread::g_runnable_threads; + auto& runnable_list = g_scheduler_data->m_runnable_threads; if (runnable_list.is_empty()) return context_switch(s_colonel_process->main_thread()); @@ -488,6 +547,7 @@ Process* Scheduler::colonel() void Scheduler::initialize() { + g_scheduler_data = new SchedulerData; s_redirection.selector = gdt_alloc_entry(); initialize_redirection(); s_colonel_process = Process::create_kernel_process("colonel", nullptr); diff --git a/Kernel/Scheduler.h b/Kernel/Scheduler.h index 5cdb2c3b64e..5363e00d9fb 100644 --- a/Kernel/Scheduler.h +++ b/Kernel/Scheduler.h @@ -2,6 +2,8 @@ #include #include +#include +#include class Process; class Thread; @@ -27,6 +29,29 @@ public: static bool is_active(); static void beep(); + template + static inline IterationDecision for_each_runnable(Callback callback) + { + return for_each_runnable_func([callback](Thread& thread) { + return callback(thread); + }); + } + + template + static inline IterationDecision for_each_nonrunnable(Callback callback) + { + return for_each_nonrunnable_func([callback](Thread& thread) { + return callback(thread); + }); + } + + static void init_thread(Thread& thread); + static void update_state_for_thread(Thread& thread); + private: static void prepare_for_iret_to_new_process(); + static IterationDecision for_each_runnable_func(Function&& callback); + static IterationDecision for_each_nonrunnable_func(Function&& callback); + }; + diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index d271172704f..6616665ca6c 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -16,9 +16,6 @@ HashTable& thread_table() return *table; } -Thread::SchedulerThreadList* Thread::g_runnable_threads; -Thread::SchedulerThreadList* Thread::g_nonrunnable_threads; - static const u32 default_kernel_stack_size = 65536; static const u32 default_userspace_stack_size = 65536; @@ -75,7 +72,7 @@ Thread::Thread(Process& process) if (m_process.pid() != 0) { InterruptDisabler disabler; thread_table().set(this); - g_nonrunnable_threads->append(*this); + Scheduler::init_thread(*this); } } @@ -514,8 +511,6 @@ Thread* Thread::clone(Process& process) void Thread::initialize() { - g_runnable_threads = new SchedulerThreadList; - g_nonrunnable_threads = new SchedulerThreadList; Scheduler::initialize(); } @@ -545,15 +540,6 @@ void Thread::set_state(State new_state) m_state = new_state; if (m_process.pid() != 0) { - SchedulerThreadList* list = nullptr; - if (is_runnable_state(new_state)) - list = g_runnable_threads; - else - list = g_nonrunnable_threads; - - if (list->contains(*this)) - return; - - list->append(*this); + Scheduler::update_state_for_thread(*this); } } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 0e531812bd9..2987474677f 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,7 +17,6 @@ class Alarm; class FileDescription; class Process; class Region; -class Thread; enum class ShouldUnblockThread { No = 0, @@ -299,10 +299,6 @@ public: template static IterationDecision for_each_living(Callback); template - static IterationDecision for_each_runnable(Callback); - template - static IterationDecision for_each_nonrunnable(Callback); - template static IterationDecision for_each(Callback); static bool is_runnable_state(Thread::State state) @@ -313,19 +309,8 @@ public: private: IntrusiveListNode m_runnable_list_node; - typedef IntrusiveList SchedulerThreadList; - -public: - static SchedulerThreadList* g_runnable_threads; - static SchedulerThreadList* g_nonrunnable_threads; - static SchedulerThreadList* thread_list_for_state(Thread::State state) - { - if (is_runnable_state(state)) - return g_runnable_threads; - return g_nonrunnable_threads; - } - private: + friend class SchedulerData; Process& m_process; int m_tid { -1 }; TSS32 m_tss; @@ -351,20 +336,6 @@ private: HashTable& thread_table(); -template -inline IterationDecision Thread::for_each_in_state(State state, Callback callback) -{ - ASSERT_INTERRUPTS_DISABLED(); - auto new_callback = [=](Thread& thread) -> IterationDecision { - if (thread.state() == state) - return callback(thread); - return IterationDecision::Continue; - }; - if (is_runnable_state(state)) - return for_each_runnable(new_callback); - return for_each_nonrunnable(new_callback); -} - template inline IterationDecision Thread::for_each_living(Callback callback) { @@ -380,38 +351,23 @@ template inline IterationDecision Thread::for_each(Callback callback) { ASSERT_INTERRUPTS_DISABLED(); - auto ret = for_each_runnable(callback); + auto ret = Scheduler::for_each_runnable(callback); if (ret == IterationDecision::Break) return ret; - return for_each_nonrunnable(callback); + return Scheduler::for_each_nonrunnable(callback); } template -inline IterationDecision Thread::for_each_runnable(Callback callback) +inline IterationDecision Thread::for_each_in_state(State state, Callback callback) { ASSERT_INTERRUPTS_DISABLED(); - auto& tl = *g_runnable_threads; - for (auto it = tl.begin(); it != tl.end();) { - auto thread = *it; - it = ++it; - if (callback(*thread) == IterationDecision::Break) - return IterationDecision::Break; - } - - return IterationDecision::Continue; + auto new_callback = [=](Thread& thread) -> IterationDecision { + if (thread.state() == state) + return callback(thread); + return IterationDecision::Continue; + }; + if (is_runnable_state(state)) + return Scheduler::for_each_runnable(new_callback); + return Scheduler::for_each_nonrunnable(new_callback); } -template -inline IterationDecision Thread::for_each_nonrunnable(Callback callback) -{ - ASSERT_INTERRUPTS_DISABLED(); - auto& tl = *g_nonrunnable_threads; - for (auto it = tl.begin(); it != tl.end();) { - auto thread = *it; - it = ++it; - if (callback(*thread) == IterationDecision::Break) - return IterationDecision::Break; - } - - return IterationDecision::Continue; -}