diff --git a/Kernel/Process.h b/Kernel/Process.h index 444b40825c..69144b35b0 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -403,7 +403,15 @@ inline void Process::for_each_thread(Callback callback) const { InterruptDisabler disabler; pid_t my_pid = pid(); - for (auto* thread = g_threads->head(); thread;) { + for (auto* thread = g_runnable_threads->head(); thread;) { + auto* next_thread = thread->next(); + if (thread->pid() == my_pid) { + if (callback(*thread) == IterationDecision::Abort) + break; + } + thread = next_thread; + } + for (auto* thread = g_nonrunnable_threads->head(); thread;) { auto* next_thread = thread->next(); if (thread->pid() == my_pid) { if (callback(*thread) == IterationDecision::Abort) diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 356a009b63..b7be97a008 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -72,7 +72,7 @@ bool Scheduler::pick_next() auto now_usec = now.tv_usec; // Check and unblock threads whose wait conditions have been met. - Thread::for_each([&] (Thread& thread) { + Thread::for_each_nonrunnable([&] (Thread& thread) { auto& process = thread.process(); if (thread.state() == Thread::BlockedSleep) { @@ -223,8 +223,8 @@ bool Scheduler::pick_next() }); #ifdef SCHEDULER_DEBUG - dbgprintf("Scheduler choices:\n"); - for (auto* thread = g_threads->head(); thread; thread = thread->next()) { + dbgprintf("Scheduler choices: (runnable threads: %p)\n", g_runnable_threads); + for (auto* thread = g_runnable_threads->head(); thread; thread = thread->next()) { //if (process->state() == Thread::BlockedWait || process->state() == Thread::BlockedSleep) // continue; auto* process = &thread->process(); @@ -232,11 +232,11 @@ bool Scheduler::pick_next() } #endif - auto* previous_head = g_threads->head(); + auto* previous_head = g_runnable_threads->head(); for (;;) { // Move head to tail. - g_threads->append(g_threads->remove_head()); - auto* thread = g_threads->head(); + g_runnable_threads->append(g_runnable_threads->remove_head()); + auto* thread = g_runnable_threads->head(); if (!thread->process().is_being_inspected() && (thread->state() == Thread::Runnable || thread->state() == Thread::Running)) { #ifdef SCHEDULER_DEBUG diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 2eb53f0902..1d511b85ed 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -5,7 +5,18 @@ #include #include -InlineLinkedList* g_threads; +HashTable& thread_table() +{ + ASSERT_INTERRUPTS_DISABLED(); + static HashTable* table; + if (!table) + table = new HashTable; + return *table; +} + +InlineLinkedList* g_runnable_threads; +InlineLinkedList* g_nonrunnable_threads; + static const dword default_kernel_stack_size = 16384; static const dword default_userspace_stack_size = 65536; @@ -61,7 +72,9 @@ Thread::Thread(Process& process) if (m_process.pid() != 0) { InterruptDisabler disabler; - g_threads->prepend(this); + thread_table().set(this); + g_nonrunnable_threads->prepend(this); + m_thread_list = g_nonrunnable_threads; } } @@ -71,7 +84,9 @@ Thread::~Thread() kfree_aligned(m_fpu_state); { InterruptDisabler disabler; - g_threads->remove(this); + if (m_thread_list) + m_thread_list->remove(this); + thread_table().remove(this); } if (g_last_fpu_thread == this) @@ -85,11 +100,11 @@ void Thread::unblock() { m_blocked_descriptor = nullptr; if (current == this) { - m_state = Thread::Running; + set_state(Thread::Running); return; } ASSERT(m_state != Thread::Runnable && m_state != Thread::Running); - m_state = Thread::Runnable; + set_state(Thread::Runnable); } void Thread::snooze_until(Alarm& alarm) @@ -509,7 +524,8 @@ KResult Thread::wait_for_connect(FileDescriptor& descriptor) void Thread::initialize() { - g_threads = new InlineLinkedList; + g_runnable_threads = new InlineLinkedList; + g_nonrunnable_threads = new InlineLinkedList; Scheduler::initialize(); } @@ -517,17 +533,26 @@ Vector Thread::all_threads() { Vector threads; InterruptDisabler disabler; - for (auto* thread = g_threads->head(); thread; thread = thread->next()) - threads.append(thread); + threads.ensure_capacity(thread_table().size()); + for (auto* thread : thread_table()) + threads.unchecked_append(thread); return threads; } bool Thread::is_thread(void* ptr) { ASSERT_INTERRUPTS_DISABLED(); - for (auto* thread = g_threads->head(); thread; thread = thread->next()) { - if (thread == ptr) - return true; - } - return false; + return thread_table().contains((Thread*)ptr); +} + +void Thread::set_state(State new_state) +{ + m_state = new_state; + auto* new_thread_list = thread_list_for_state(new_state); + if (m_thread_list == new_thread_list) + return; + if (m_thread_list) + m_thread_list->remove(this); + new_thread_list->append(this); + m_thread_list = new_thread_list; } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 3afc9d5d90..ecd058c2a6 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -15,6 +15,7 @@ class Alarm; class FileDescriptor; class Process; class Region; +class Thread; enum class ShouldUnblockThread { No = 0, Yes }; @@ -24,6 +25,9 @@ struct SignalActionData { int flags { 0 }; }; +extern InlineLinkedList* g_runnable_threads; +extern InlineLinkedList* g_nonrunnable_threads; + class Thread : public InlineLinkedListNode { friend class Process; friend class Scheduler; @@ -105,7 +109,7 @@ public: dword kernel_stack_for_signal_handler_base() const { return m_kernel_stack_for_signal_handler_region ? m_kernel_stack_for_signal_handler_region->laddr().get() : 0; } void set_selector(word s) { m_far_ptr.selector = s; } - void set_state(State s) { m_state = s; } + void set_state(State); void send_signal(byte signal, Process* sender); @@ -129,10 +133,26 @@ public: Thread* m_prev { nullptr }; Thread* m_next { nullptr }; + InlineLinkedList* thread_list() { return m_thread_list; } + template static void for_each_in_state(State, Callback); template static void for_each_living(Callback); + template static void for_each_runnable(Callback); + template static void for_each_nonrunnable(Callback); template static void for_each(Callback); + static bool is_runnable_state(Thread::State state) + { + return state == Thread::State::Running || state == Thread::State::Runnable; + } + + static InlineLinkedList* thread_list_for_state(Thread::State state) + { + if (is_runnable_state(state)) + return g_runnable_threads; + return g_nonrunnable_threads; + } + private: Process& m_process; int m_tid { -1 }; @@ -158,13 +178,14 @@ private: Vector m_select_write_fds; Vector m_select_exceptional_fds; FPUState* m_fpu_state { nullptr }; + InlineLinkedList* m_thread_list { nullptr }; State m_state { Invalid }; bool m_select_has_timeout { false }; bool m_has_used_fpu { false }; bool m_was_interrupted_while_blocked { false }; }; -extern InlineLinkedList* g_threads; +HashTable& thread_table(); const char* to_string(Thread::State); @@ -172,7 +193,7 @@ template inline void Thread::for_each_in_state(State state, Callback callback) { ASSERT_INTERRUPTS_DISABLED(); - for (auto* thread = g_threads->head(); thread;) { + for (auto* thread = thread_list_for_state(state)->head(); thread;) { auto* next_thread = thread->next(); if (thread->state() == state) callback(*thread); @@ -184,7 +205,13 @@ template inline void Thread::for_each_living(Callback callback) { ASSERT_INTERRUPTS_DISABLED(); - for (auto* thread = g_threads->head(); thread;) { + for (auto* thread = g_runnable_threads->head(); thread;) { + auto* next_thread = thread->next(); + if (thread->state() != Thread::State::Dead && thread->state() != Thread::State::Dying) + callback(*thread); + thread = next_thread; + } + for (auto* thread = g_nonrunnable_threads->head(); thread;) { auto* next_thread = thread->next(); if (thread->state() != Thread::State::Dead && thread->state() != Thread::State::Dying) callback(*thread); @@ -196,7 +223,15 @@ template inline void Thread::for_each(Callback callback) { ASSERT_INTERRUPTS_DISABLED(); - for (auto* thread = g_threads->head(); thread;) { + for_each_runnable(callback); + for_each_nonrunnable(callback); +} + +template +inline void Thread::for_each_runnable(Callback callback) +{ + ASSERT_INTERRUPTS_DISABLED(); + for (auto* thread = g_runnable_threads->head(); thread;) { auto* next_thread = thread->next(); if (callback(*thread) == IterationDecision::Abort) return; @@ -204,3 +239,14 @@ inline void Thread::for_each(Callback callback) } } +template +inline void Thread::for_each_nonrunnable(Callback callback) +{ + ASSERT_INTERRUPTS_DISABLED(); + for (auto* thread = g_nonrunnable_threads->head(); thread;) { + auto* next_thread = thread->next(); + if (callback(*thread) == IterationDecision::Abort) + return; + thread = next_thread; + } +}