diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index cc11b941da..39e17a30b7 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -291,14 +291,14 @@ bool Scheduler::pick_next() // Dispatch any pending signals. // FIXME: Do we really need this to be a separate pass over the process list? - Thread::for_each_living([](Thread& thread) { + Thread::for_each_living([](Thread& thread) -> IterationDecision { if (!thread.has_unmasked_pending_signals()) - return true; + return IterationDecision::Continue; // FIXME: It would be nice if the Scheduler didn't have to worry about who is "current" // For now, avoid dispatching signals to "current" and do it in a scheduling pass // while some other process is interrupted. Otherwise a mess will be made. if (&thread == current) - return true; + return IterationDecision::Continue; // We know how to interrupt blocked processes, but if they are just executing // at some random point in the kernel, let them continue. They'll be in userspace // sooner or later and we can deliver the signal then. @@ -306,17 +306,17 @@ bool Scheduler::pick_next() // signal and dispatch it then and there? Would that be doable without the // syscall effectively being "interrupted" despite having completed? if (thread.in_kernel() && !thread.is_blocked() && !thread.is_stopped()) - return true; + return IterationDecision::Continue; // NOTE: dispatch_one_pending_signal() may unblock the process. bool was_blocked = thread.is_blocked(); if (thread.dispatch_one_pending_signal() == ShouldUnblockThread::No) - return true; + return IterationDecision::Continue; if (was_blocked) { dbgprintf("Unblock %s(%u) due to signal\n", thread.process().name().characters(), thread.pid()); thread.m_was_interrupted_while_blocked = true; thread.unblock(); } - return true; + return IterationDecision::Continue; }); #ifdef SCHEDULER_RUNNABLE_DEBUG diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 0f71f37dd3..b8fca99784 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -178,6 +178,7 @@ void Thread::finalize_dying_threads() InterruptDisabler disabler; for_each_in_state(Thread::State::Dying, [&](Thread& thread) { dying_threads.append(&thread); + return IterationDecision::Continue; }); } for (auto* thread : dying_threads) diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 57ad89ad3f..c5ac7eb032 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -262,15 +262,15 @@ public: void set_thread_list(InlineLinkedList*); template - static void for_each_in_state(State, Callback); + static IterationDecision for_each_in_state(State, Callback); template - static void for_each_living(Callback); + static IterationDecision for_each_living(Callback); template - static void for_each_runnable(Callback); + static IterationDecision for_each_runnable(Callback); template - static void for_each_nonrunnable(Callback); + static IterationDecision for_each_nonrunnable(Callback); template - static void for_each(Callback); + static IterationDecision for_each(Callback); static bool is_runnable_state(Thread::State state) { @@ -313,63 +313,77 @@ private: HashTable& thread_table(); template -inline void Thread::for_each_in_state(State state, Callback callback) +inline IterationDecision Thread::for_each_in_state(State state, Callback callback) { ASSERT_INTERRUPTS_DISABLED(); for (auto* thread = thread_list_for_state(state)->head(); thread;) { auto* next_thread = thread->next(); - if (thread->state() == state) - callback(*thread); + if (thread->state() == state) { + if (callback(*thread) == IterationDecision::Break) + return IterationDecision::Break; + } thread = next_thread; } + + return IterationDecision::Continue; } template -inline void Thread::for_each_living(Callback callback) +inline IterationDecision Thread::for_each_living(Callback callback) { ASSERT_INTERRUPTS_DISABLED(); 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); + if (callback(*thread) == IterationDecision::Break) + return IterationDecision::Break; 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); + if (callback(*thread) == IterationDecision::Break) + return IterationDecision::Break; thread = next_thread; } + + return IterationDecision::Continue; } template -inline void Thread::for_each(Callback callback) +inline IterationDecision Thread::for_each(Callback callback) { ASSERT_INTERRUPTS_DISABLED(); - for_each_runnable(callback); - for_each_nonrunnable(callback); + auto ret = for_each_runnable(callback); + if (ret == IterationDecision::Break) + return ret; + return for_each_nonrunnable(callback); } template -inline void Thread::for_each_runnable(Callback callback) +inline IterationDecision 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::Break) - return; + return IterationDecision::Break; thread = next_thread; } + + return IterationDecision::Continue; } template -inline void Thread::for_each_nonrunnable(Callback callback) +inline IterationDecision 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::Break) - return; + return IterationDecision::Break; thread = next_thread; } + + return IterationDecision::Continue; }