mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 15:28:11 +00:00
Kernel: Avoid unnecessary context switch when no other thread is ready
If no other thread is ready to be run we don't need to switch to the idle thread and wait for the next timer interrupt. We can just give the thread another timeslice and keep it running.
This commit is contained in:
parent
dfc33cd412
commit
60a559af7e
2 changed files with 38 additions and 0 deletions
|
@ -105,6 +105,33 @@ Thread& Scheduler::pull_next_runnable_thread()
|
|||
return *Processor::idle_thread();
|
||||
}
|
||||
|
||||
Thread* Scheduler::peek_next_runnable_thread()
|
||||
{
|
||||
auto affinity_mask = 1u << Processor::current().id();
|
||||
|
||||
ScopedSpinLock lock(g_ready_queues_lock);
|
||||
auto priority_mask = g_ready_queues_mask;
|
||||
while (priority_mask != 0) {
|
||||
auto priority = __builtin_ffsl(priority_mask);
|
||||
VERIFY(priority > 0);
|
||||
auto& ready_queue = g_ready_queues[--priority];
|
||||
for (auto& thread : ready_queue.thread_list) {
|
||||
VERIFY(thread.m_runnable_priority == (int)priority);
|
||||
if (thread.is_active())
|
||||
continue;
|
||||
if (!(thread.affinity() & affinity_mask))
|
||||
continue;
|
||||
return &thread;
|
||||
}
|
||||
priority_mask &= ~(1u << priority);
|
||||
}
|
||||
|
||||
// Unlike in pull_next_runnable_thread() we don't want to fall back to
|
||||
// the idle thread. We just want to see if we have any other thread ready
|
||||
// to be scheduled.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Scheduler::dequeue_runnable_thread(Thread& thread, bool check_affinity)
|
||||
{
|
||||
if (thread.is_idle_thread())
|
||||
|
@ -426,6 +453,16 @@ void Scheduler::timer_tick(const RegisterState& regs)
|
|||
if (current_thread->tick())
|
||||
return;
|
||||
|
||||
if (!current_thread->is_idle_thread() && !peek_next_runnable_thread()) {
|
||||
// If no other thread is ready to be scheduled we don't need to
|
||||
// switch to the idle thread. Just give the current thread another
|
||||
// time slice and let it run!
|
||||
current_thread->set_ticks_left(time_slice_for(*current_thread));
|
||||
current_thread->did_schedule();
|
||||
dbgln_if(SCHEDULER_DEBUG, "Scheduler[{}]: No other threads ready, give {} another timeslice", Processor::id(), *current_thread);
|
||||
return;
|
||||
}
|
||||
|
||||
VERIFY_INTERRUPTS_DISABLED();
|
||||
VERIFY(Processor::current().in_irq());
|
||||
Processor::current().invoke_scheduler_async();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue