1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:28:11 +00:00

Kernel: Separate runnable thread queues by priority

This patch introduces three separate thread queues, one for each thread
priority available to userspace (Low, Normal and High.)

Each queue operates in a round-robin fashion, but we now always prefer
to schedule the highest priority thread that currently wants to run.

There are tons of tweaks and improvements that we can and should make
to this mechanism, but I think this is a step in the right direction.

This makes WindowServer significantly more responsive while one of its
clients is burning CPU. :^)
This commit is contained in:
Andreas Kling 2019-12-27 00:46:38 +01:00
parent 23e16a3e2e
commit abdd5aa08a
2 changed files with 62 additions and 37 deletions

View file

@ -40,7 +40,7 @@ enum class ThreadPriority : u8 {
Low,
Normal,
High,
First = Idle,
First = Low,
Last = High,
};
@ -501,13 +501,15 @@ const LogStream& operator<<(const LogStream&, const Thread&);
struct SchedulerData {
typedef IntrusiveList<Thread, &Thread::m_runnable_list_node> ThreadList;
ThreadList m_runnable_threads;
static constexpr size_t num_thread_priorities = (size_t)ThreadPriority::Last - (size_t)ThreadPriority::First + 1;
ThreadList m_runnable_threads[num_thread_priorities];
ThreadList m_nonrunnable_threads;
ThreadList& thread_list_for_state(Thread::State state)
ThreadList& thread_list_for_state_and_priority(Thread::State state, ThreadPriority priority)
{
if (Thread::is_runnable_state(state))
return m_runnable_threads;
return m_runnable_threads[(u8)priority - (u8)ThreadPriority::First];
return m_nonrunnable_threads;
}
};
@ -516,12 +518,13 @@ template<typename Callback>
inline IterationDecision Scheduler::for_each_runnable(Callback 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;
for (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;