diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 54576f40a0..457bc1d4b4 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -53,15 +53,8 @@ public: bool m_in_scheduler { true }; }; -SchedulerData* g_scheduler_data; RecursiveSpinLock g_scheduler_lock; -void Scheduler::init_thread(Thread& thread) -{ - ASSERT(g_scheduler_data); - g_scheduler_data->m_nonrunnable_threads.append(thread); -} - static u32 time_slice_for(const Thread& thread) { // One time slice unit == 4ms (assuming 250 ticks/second) @@ -238,36 +231,29 @@ bool Scheduler::pick_next() } if constexpr (SCHEDULER_RUNNABLE_DEBUG) { - dbgln("Scheduler[{}j]: Non-runnables:", Processor::id()); - Scheduler::for_each_nonrunnable([&](Thread& thread) -> IterationDecision { - if (thread.state() == Thread::Dying) { + dbgln("Scheduler thread list:", Processor::id()); + Thread::for_each([&](Thread& thread) -> IterationDecision { + switch (thread.state()) { + case Thread::Dying: dbgln(" {:12} {} @ {:04x}:{:08x} Finalizable: {}", thread.state_string(), thread, thread.tss().cs, thread.tss().eip, thread.is_finalizable()); - } else { - dbgln(" {:12} {} @ {:04x}:{:08x}", + break; + default: + dbgln(" {:12} Pr:{:2} {} @ {:04x}:{:08x}", thread.state_string(), + thread.priority(), thread, thread.tss().cs, thread.tss().eip); + break; } return IterationDecision::Continue; }); - - dbgln("Scheduler[{}j]: Runnables:", Processor::id()); - Scheduler::for_each_runnable([](Thread& thread) -> IterationDecision { - dbgln(" {:2} {:12} @ {:04x}:{:08x}", - thread.priority(), - thread.state_string(), - thread.tss().cs, - thread.tss().eip); - - return IterationDecision::Continue; - }); } auto pending_beneficiary = scheduler_data.m_pending_beneficiary.strong_ref(); @@ -507,7 +493,6 @@ void Scheduler::initialize() ASSERT(&Processor::current() != nullptr); // sanity check RefPtr idle_thread; - g_scheduler_data = new SchedulerData; g_finalizer_wait_queue = new WaitQueue; g_ready_queues = new ThreadReadyQueue[g_ready_queue_buckets]; diff --git a/Kernel/Scheduler.h b/Kernel/Scheduler.h index 08b8d8f79c..fec07e9f74 100644 --- a/Kernel/Scheduler.h +++ b/Kernel/Scheduler.h @@ -40,12 +40,10 @@ class Process; class Thread; class WaitQueue; struct RegisterState; -struct SchedulerData; extern Thread* g_finalizer; extern WaitQueue* g_finalizer_wait_queue; extern Atomic g_finalizer_has_work; -extern SchedulerData* g_scheduler_data; extern RecursiveSpinLock g_scheduler_lock; class Scheduler { @@ -73,14 +71,6 @@ public: static Thread& pull_next_runnable_thread(); static bool dequeue_runnable_thread(Thread&, bool = false); static void queue_runnable_thread(Thread&); - - template - static inline IterationDecision for_each_runnable(Callback); - - template - static inline IterationDecision for_each_nonrunnable(Callback); - - static void init_thread(Thread& thread); }; } diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 79c4392d77..aff9e9c8d5 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -45,6 +45,14 @@ namespace Kernel { +SpinLock Thread::g_tid_map_lock; +HashMap* Thread::g_tid_map; + +void Thread::initialize() +{ + g_tid_map = new HashMap(); +} + Thread::Thread(NonnullRefPtr process) : m_process(move(process)) , m_name(m_process->name()) @@ -59,6 +67,11 @@ Thread::Thread(NonnullRefPtr process) } else { m_tid = Process::allocate_pid().value(); } + { + ScopedSpinLock lock(g_tid_map_lock); + auto result = g_tid_map->set(m_tid, this); + ASSERT(result == AK::HashSetResult::InsertedNewEntry); + } if constexpr (THREAD_DEBUG) dbgln("Created new thread {}({}:{})", m_process->name(), m_process->pid().value(), m_tid.value()); set_default_signal_dispositions(); @@ -115,9 +128,6 @@ Thread::Thread(NonnullRefPtr process) // thread is ready to be cleaned up. ref(); guard.disarm(); - - if (m_process->pid() != 0) - Scheduler::init_thread(*this); } Thread::~Thread() @@ -131,11 +141,14 @@ Thread::~Thread() // the middle of being destroyed. ScopedSpinLock lock(g_scheduler_lock); ASSERT(!m_process_thread_list_node.is_in_list()); - g_scheduler_data->thread_list_for_state(m_state).remove(*this); // We shouldn't be queued ASSERT(m_runnable_priority < 0); - ASSERT(!m_runnable_list_node.is_in_list()); + } + { + ScopedSpinLock lock(g_tid_map_lock); + auto result = g_tid_map->remove(m_tid); + ASSERT(result); } } @@ -903,11 +916,6 @@ void Thread::set_state(State new_state, u8 stop_signal) dbgln("Set thread {} state to {}", *this, state_string()); } - if (m_process->pid() != 0) { - update_state_for_thread(previous_state); - ASSERT(g_scheduler_data->has_thread(*this)); - } - if (previous_state == Runnable) { Scheduler::dequeue_runnable_thread(*this); } else if (previous_state == Stopped) { @@ -952,24 +960,6 @@ void Thread::set_state(State new_state, u8 stop_signal) } } -void Thread::update_state_for_thread(Thread::State previous_state) -{ - ASSERT_INTERRUPTS_DISABLED(); - ASSERT(g_scheduler_data); - ASSERT(g_scheduler_lock.own_lock()); - auto& previous_list = g_scheduler_data->thread_list_for_state(previous_state); - auto& list = g_scheduler_data->thread_list_for_state(state()); - - if (&previous_list != &list) { - previous_list.remove(*this); - } - - if (list.contains(*this)) - return; - - list.append(*this); -} - String Thread::backtrace() { return backtrace_impl(); @@ -1093,14 +1083,12 @@ const LogStream& operator<<(const LogStream& stream, const Thread& value) RefPtr Thread::from_tid(ThreadID tid) { RefPtr found_thread; - ScopedSpinLock lock(g_scheduler_lock); - Thread::for_each([&](auto& thread) { - if (thread.tid() == tid) { - found_thread = &thread; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); + { + ScopedSpinLock lock(g_tid_map_lock); + auto it = g_tid_map->find(tid); + if (it != g_tid_map->end()) + found_thread = it->value; + } return found_thread; } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index f3f1bf9561..70bdf6bfc1 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -27,6 +27,7 @@ #pragma once #include +#include #include #include #include @@ -87,12 +88,17 @@ class Thread friend class Scheduler; friend class ThreadReadyQueue; + static SpinLock g_tid_map_lock; + static HashMap* g_tid_map; + public: inline static Thread* current() { return Processor::current_thread(); } + static void initialize(); + explicit Thread(NonnullRefPtr); ~Thread(); @@ -1090,8 +1096,6 @@ public: template static IterationDecision for_each_in_state(State, Callback); template - static IterationDecision for_each_living(Callback); - template static IterationDecision for_each(Callback); [[nodiscard]] static bool is_runnable_state(Thread::State state) @@ -1166,10 +1170,8 @@ public: private: IntrusiveListNode m_process_thread_list_node; - IntrusiveListNode m_runnable_list_node; int m_runnable_priority { -1 }; - friend struct SchedulerData; friend class WaitQueue; class JoinBlockCondition : public BlockCondition { @@ -1304,100 +1306,38 @@ private: void yield_without_holding_big_lock(); void donate_without_holding_big_lock(RefPtr&, const char*); void yield_while_not_holding_big_lock(); - void update_state_for_thread(Thread::State previous_state); void drop_thread_count(bool); }; -template -inline IterationDecision Thread::for_each_living(Callback callback) -{ - ASSERT_INTERRUPTS_DISABLED(); - return Thread::for_each([callback](Thread& thread) -> IterationDecision { - if (thread.state() != Thread::State::Dead && thread.state() != Thread::State::Dying) - return callback(thread); - return IterationDecision::Continue; - }); -} - template inline IterationDecision Thread::for_each(Callback callback) { - ASSERT_INTERRUPTS_DISABLED(); - ScopedSpinLock lock(g_scheduler_lock); - auto ret = Scheduler::for_each_runnable(callback); - if (ret == IterationDecision::Break) - return ret; - return Scheduler::for_each_nonrunnable(callback); + ScopedSpinLock lock(g_tid_map_lock); + for (auto& it : *g_tid_map) { + IterationDecision decision = callback(*it.value); + if (decision != IterationDecision::Continue) + return decision; + } + return IterationDecision::Continue; } template inline IterationDecision Thread::for_each_in_state(State state, Callback callback) { - ASSERT_INTERRUPTS_DISABLED(); - ScopedSpinLock lock(g_scheduler_lock); - 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); + ScopedSpinLock lock(g_tid_map_lock); + for (auto& it : *g_tid_map) { + auto& thread = *it.value; + if (thread.state() != state) + continue; + IterationDecision decision = callback(thread); + if (decision != IterationDecision::Continue) + return decision; + } + return IterationDecision::Continue; } const LogStream& operator<<(const LogStream&, const Thread&); -struct SchedulerData { - typedef IntrusiveList ThreadList; - - ThreadList m_runnable_threads; - ThreadList m_nonrunnable_threads; - - bool has_thread(Thread& thread) const - { - return m_runnable_threads.contains(thread) || m_nonrunnable_threads.contains(thread); - } - - ThreadList& thread_list_for_state(Thread::State state) - { - if (Thread::is_runnable_state(state)) - return m_runnable_threads; - return m_nonrunnable_threads; - } -}; - -template -inline IterationDecision Scheduler::for_each_runnable(Callback callback) -{ - ASSERT_INTERRUPTS_DISABLED(); - ASSERT(g_scheduler_lock.own_lock()); - 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; -} - -template -inline IterationDecision Scheduler::for_each_nonrunnable(Callback callback) -{ - ASSERT_INTERRUPTS_DISABLED(); - ASSERT(g_scheduler_lock.own_lock()); - 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; -} - } template<> diff --git a/Kernel/init.cpp b/Kernel/init.cpp index d216c9dfae..c5ca51b983 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -162,6 +162,7 @@ extern "C" [[noreturn]] void init() } VirtualConsole::switch_to(0); + Thread::initialize(); Process::initialize(); Scheduler::initialize();