From 378e8aa159caea08e869789ae40f73cea1480322 Mon Sep 17 00:00:00 2001 From: Avi Kivity <avi@cloudius-systems.com> Date: Sun, 3 Mar 2013 18:32:42 +0200 Subject: [PATCH] sched: preemption Split the core scheduler into a function for calling from interrupts, and a wrapper for calling it from normal paths. Call the preemptible path from interrupt handlers. --- arch/x64/exceptions.cc | 4 ++++ core/sched.cc | 42 ++++++++++++++++++++++++++++-------------- include/sched.hh | 2 ++ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/arch/x64/exceptions.cc b/arch/x64/exceptions.cc index d0351ce43..8ba6e909a 100644 --- a/arch/x64/exceptions.cc +++ b/arch/x64/exceptions.cc @@ -3,6 +3,7 @@ #include "processor.hh" #include "interrupt.hh" #include <boost/format.hpp> +#include "sched.hh" #include "debug.hh" typedef boost::format fmt; @@ -117,7 +118,10 @@ void interrupt(exception_frame* frame) unsigned vector = frame->error_code; idt.invoke_interrupt(vector); processor::wrmsr(0x80b, 0); // EOI + // must call scheduler after EOI, or it may switch contexts and miss the EOI current_interrupt_frame = nullptr; + // FIXME: layering violation + sched::preempt(); } #define DUMMY_HANDLER(x) \ diff --git a/core/sched.cc b/core/sched.cc index 51d4bf891..5656dd398 100644 --- a/core/sched.cc +++ b/core/sched.cc @@ -20,8 +20,6 @@ unsigned __thread preempt_counter; elf::tls_data tls; -// currently the scheduler will poll right after an interrupt, so no -// need to do anything. inter_processor_interrupt wakeup_ipi{[] {}}; } @@ -44,23 +42,29 @@ void cpu::schedule(bool yield) { // FIXME: drive by IPI handle_incoming_wakeups(); - thread* p = thread::current(); - if (p->_status.load() == thread::status::running && !yield) { - return; - } with_lock(irq_lock, [this] { - assert(!runqueue.empty()); - auto n = &runqueue.front(); - runqueue.pop_front(); - assert(n->_status.load() == thread::status::queued); - n->_status.store(thread::status::running); - if (n != thread::current()) { - n->switch_to(); - } + reschedule_from_interrupt(); }); } +void cpu::reschedule_from_interrupt() +{ + handle_incoming_wakeups(); + thread* p = thread::current(); + if (p->_status == thread::status::running) { + p->_status.store(thread::status::queued); + runqueue.push_back(*p); + } + auto n = &runqueue.front(); + runqueue.pop_front(); + assert(n->_status.load() == thread::status::queued); + n->_status.store(thread::status::running); + if (n != thread::current()) { + n->switch_to(); + } +} + void cpu::do_idle() { do { @@ -261,6 +265,9 @@ void thread::wake() // FIXME: warrant an interruption if (_cpu != current()->tcpu()) { wakeup_ipi.send(_cpu); + } else if (arch::irq_enabled()) { + _cpu->schedule(); + // We'll also reschedule at the end of an interrupt if needed } } @@ -355,6 +362,13 @@ void preempt_enable() // FIXME: may need to schedule() here if a high prio thread is waiting } +void preempt() +{ + if (!preempt_counter) { + sched::cpu::current()->reschedule_from_interrupt(); + } +} + timer_list::callback_dispatch::callback_dispatch() { clock_event->set_callback(this); diff --git a/include/sched.hh b/include/sched.hh index db737a0f3..200413c72 100644 --- a/include/sched.hh +++ b/include/sched.hh @@ -266,8 +266,10 @@ struct cpu { void do_idle(); void load_balance(); unsigned load(); + void reschedule_from_interrupt(); }; +void preempt(); void preempt_disable(); void preempt_enable(); -- GitLab