diff options
Diffstat (limited to 'Kernel/Scheduler.cpp')
-rw-r--r-- | Kernel/Scheduler.cpp | 109 |
1 files changed, 47 insertions, 62 deletions
diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index febb8a1f19..0f270dd2ff 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -1,3 +1,4 @@ +#include <AK/QuickSort.h> #include <AK/TemporaryChange.h> #include <Kernel/Arch/i386/PIT.h> #include <Kernel/FileSystem/FileDescription.h> @@ -21,7 +22,7 @@ void Scheduler::init_thread(Thread& thread) void Scheduler::update_state_for_thread(Thread& thread) { ASSERT_INTERRUPTS_DISABLED(); - auto& list = g_scheduler_data->thread_list_for_state_and_priority(thread.state(), thread.priority()); + auto& list = g_scheduler_data->thread_list_for_state(thread.state()); if (list.contains(thread)) return; @@ -29,35 +30,12 @@ void Scheduler::update_state_for_thread(Thread& thread) list.append(thread); } -template<typename Callback> -static inline IterationDecision for_each_runnable_with_priority(ThreadPriority priority, Callback callback) -{ - ASSERT_INTERRUPTS_DISABLED(); - auto& tl = g_scheduler_data->m_runnable_threads[(u8)priority - (u8)ThreadPriority::First]; - for (auto it = tl.begin(); it != tl.end();) { - auto& thread = *it; - it = ++it; - if (callback(thread) == IterationDecision::Break) - return IterationDecision::Break; - } - - return IterationDecision::Continue; -} - -static u32 time_slice_for(ThreadPriority priority) +static u32 time_slice_for(const Thread& thread) { // One time slice unit == 1ms - switch (priority) { - case ThreadPriority::High: - return 20; - case ThreadPriority::Normal: - return 15; - case ThreadPriority::Low: - return 5; - case ThreadPriority::Idle: + if (&thread == g_colonel) return 1; - } - ASSERT_NOT_REACHED(); + return 10; } Thread* current; @@ -364,46 +342,54 @@ bool Scheduler::pick_next() #ifdef SCHEDULER_RUNNABLE_DEBUG dbgprintf("Non-runnables:\n"); Scheduler::for_each_nonrunnable([](Thread& thread) -> IterationDecision { - auto& process = thread.process(); - dbgprintf("[K%x] %-12s %s(%u:%u) @ %w:%x\n", &process, thread.state_string(), process.name().characters(), process.pid(), thread.tid(), thread.tss().cs, thread.tss().eip); + dbgprintf(" %-12s %s(%u:%u) @ %w:%x\n", thread.state_string(), thread.name().characters(), thread.pid(), thread.tid(), thread.tss().cs, thread.tss().eip); return IterationDecision::Continue; }); - for (u8 priority = (u8)ThreadPriority::Last; priority >= (u8)ThreadPriority::First; --priority) { - dbgprintf("Runnables (%s):\n", to_string((ThreadPriority)priority)); - for_each_runnable_with_priority((ThreadPriority)priority, [](Thread& thread) -> IterationDecision { - auto& process = thread.process(); - dbgprintf("[K%x] %-12s %s(%u:%u) @ %w:%x\n", &process, thread.state_string(), process.name().characters(), process.pid(), thread.tid(), thread.tss().cs, thread.tss().eip); - return IterationDecision::Continue; - }); - } + dbgprintf("Runnables:\n"); + Scheduler::for_each_runnable([](Thread& thread) -> IterationDecision { + dbgprintf(" %3u/%2u %-12s %s(%u:%u) @ %w:%x\n", thread.effective_priority(), thread.priority(), thread.state_string(), thread.name().characters(), thread.pid(), thread.tid(), thread.tss().cs, thread.tss().eip); + return IterationDecision::Continue; + }); #endif - for (u8 priority = (u8)ThreadPriority::Last; priority >= (u8)ThreadPriority::First; --priority) { - auto& runnable_list = g_scheduler_data->m_runnable_threads[priority - (u8)ThreadPriority::First]; - if (runnable_list.is_empty()) - continue; + Vector<Thread*, 128> sorted_runnables; + for_each_runnable([&sorted_runnables](auto& thread) { + sorted_runnables.append(&thread); + return IterationDecision::Continue; + }); + quick_sort(sorted_runnables.begin(), sorted_runnables.end(), [](auto& a, auto& b) { return a->effective_priority() >= b->effective_priority(); }); - auto* previous_head = runnable_list.first(); - for (;;) { - // Move head to tail. - runnable_list.append(*runnable_list.first()); - auto* thread = runnable_list.first(); + Thread* thread_to_schedule = nullptr; - if (!thread->process().is_being_inspected() && (thread->state() == Thread::Runnable || thread->state() == Thread::Running)) { -#ifdef SCHEDULER_DEBUG - dbgprintf("switch to %s(%u:%u) @ %w:%x\n", thread->process().name().characters(), thread->process().pid(), thread->tid(), thread->tss().cs, thread->tss().eip); -#endif - return context_switch(*thread); - } + for (auto* thread : sorted_runnables) { + if (thread->process().is_being_inspected()) + continue; - if (thread == previous_head) - break; + ASSERT(thread->state() == Thread::Runnable || thread->state() == Thread::Running); + + if (!thread_to_schedule) { + thread->m_extra_priority = 0; + thread_to_schedule = thread; + } else { + thread->m_extra_priority++; } } - // Nothing wants to run. Send in the colonel! - return context_switch(*g_colonel); + + if (!thread_to_schedule) + thread_to_schedule = g_colonel; + +#ifdef SCHEDULER_DEBUG + dbgprintf("switch to %s(%u:%u) @ %w:%x\n", + thread_to_schedule->name().characters(), + thread_to_schedule->pid(), + thread_to_schedule->tid(), + thread_to_schedule->tss().cs, + thread_to_schedule->tss().eip); +#endif + + return context_switch(*thread_to_schedule); } bool Scheduler::donate_to(Thread* beneficiary, const char* reason) @@ -417,7 +403,7 @@ bool Scheduler::donate_to(Thread* beneficiary, const char* reason) if (!beneficiary || beneficiary->state() != Thread::Runnable || ticks_left <= 1) return yield(); - unsigned ticks_to_donate = min(ticks_left - 1, time_slice_for(beneficiary->priority())); + unsigned ticks_to_donate = min(ticks_left - 1, time_slice_for(*beneficiary)); #ifdef SCHEDULER_DEBUG dbgprintf("%s(%u:%u) donating %u ticks to %s(%u:%u), reason=%s\n", current->process().name().characters(), current->pid(), current->tid(), ticks_to_donate, beneficiary->process().name().characters(), beneficiary->pid(), beneficiary->tid(), reason); #endif @@ -459,7 +445,7 @@ void Scheduler::switch_now() bool Scheduler::context_switch(Thread& thread) { - thread.set_ticks_left(time_slice_for(thread.priority())); + thread.set_ticks_left(time_slice_for(thread)); thread.did_schedule(); if (current == &thread) @@ -472,10 +458,10 @@ bool Scheduler::context_switch(Thread& thread) current->set_state(Thread::Runnable); #ifdef LOG_EVERY_CONTEXT_SWITCH - dbgprintf("Scheduler: %s(%u:%u) -> %s(%u:%u) [%s] %w:%x\n", + dbgprintf("Scheduler: %s(%u:%u) -> %s(%u:%u) [%u] %w:%x\n", current->process().name().characters(), current->process().pid(), current->tid(), thread.process().name().characters(), thread.process().pid(), thread.tid(), - to_string(thread.priority()), + thread.priority(), thread.tss().cs, thread.tss().eip); #endif } @@ -552,8 +538,7 @@ void Scheduler::initialize() s_redirection.selector = gdt_alloc_entry(); initialize_redirection(); s_colonel_process = Process::create_kernel_process(g_colonel, "colonel", nullptr); - // Make sure the colonel uses a smallish time slice. - g_colonel->set_priority(ThreadPriority::Idle); + g_colonel->set_priority(THREAD_PRIORITY_MIN); load_task_register(s_redirection.selector); } |