From 2ecf1d887b44c8d5874cf97cd1dbe78886030a73 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Wed, 20 Feb 2019 15:26:56 +0100 Subject: [PATCH] hw: schedule on demand (Fix #3157) --- repos/base-hw/src/core/kernel/cpu.cc | 24 ++++++------ repos/base-hw/src/core/kernel/cpu.h | 1 - .../base-hw/src/core/kernel/cpu_scheduler.cc | 38 +++++++++++++++---- repos/base-hw/src/core/kernel/cpu_scheduler.h | 6 ++- repos/base-hw/src/core/kernel/timer.cc | 11 +++++- repos/base-hw/src/core/kernel/timer.h | 20 +++++++++- .../src/core/spec/riscv/kernel/thread.cc | 7 +++- 7 files changed, 79 insertions(+), 28 deletions(-) diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index e8c5babea3..e8bcf82871 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -164,22 +164,20 @@ bool Cpu::interrupt(unsigned const irq_id) Cpu_job & Cpu::schedule() { /* update scheduler */ - time_t quota = _timer.update_time(); Job & old_job = scheduled_job(); old_job.exception(*this); - _timer.process_timeouts(); - _scheduler.update(quota); - /* get new job */ - Job & new_job = scheduled_job(); - quota = _scheduler.head_quota(); - - _timer.set_timeout(this, quota); - - _timer.schedule_timeout(); + if (_scheduler.need_to_schedule()) { + time_t quota = _timer.update_time(); + _timer.process_timeouts(); + _scheduler.update(quota); + quota = _scheduler.head_quota(); + _timer.set_timeout(this, quota); + _timer.schedule_timeout(); + } /* return new job */ - return new_job; + return scheduled_job(); } @@ -195,9 +193,9 @@ addr_t Cpu::stack_start() { Cpu::Cpu(unsigned const id, Pic & pic, Inter_processor_work_list & global_work_list) : - _id(id), _pic(pic), _timer(_id), + _id(id), _pic(pic), _timer(*this), _scheduler(&_idle, _quota(), _fill()), _idle(*this), - _ipi_irq(*this), _timer_irq(_timer.interrupt_id(), *this), + _ipi_irq(*this), _global_work_list(global_work_list) { _arch_init(); } diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h index f32dfeb3ab..4ddac6b3e0 100644 --- a/repos/base-hw/src/core/kernel/cpu.h +++ b/repos/base-hw/src/core/kernel/cpu.h @@ -116,7 +116,6 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout Cpu_scheduler _scheduler; Idle_thread _idle; Ipi _ipi_irq; - Irq _timer_irq; /* timer IRQ implemented as empty event */ Inter_processor_work_list &_global_work_list; Inter_processor_work_list _local_work_list {}; diff --git a/repos/base-hw/src/core/kernel/cpu_scheduler.cc b/repos/base-hw/src/core/kernel/cpu_scheduler.cc index 5595636712..1a378f924a 100644 --- a/repos/base-hw/src/core/kernel/cpu_scheduler.cc +++ b/repos/base-hw/src/core/kernel/cpu_scheduler.cc @@ -101,7 +101,7 @@ unsigned Cpu_scheduler::_trim_consumption(unsigned & q) { q = Genode::min(Genode::min(q, _head_quota), _residual); if (!_head_yields) { return _head_quota - q; } - _head_yields = 0; + _head_yields = false; return 0; } @@ -129,6 +129,8 @@ void Cpu_scheduler::_quota_adaption(Share * const s, unsigned const q) void Cpu_scheduler::update(unsigned q) { + _need_to_schedule = false; + /* do not detract the quota if the head context was removed even now */ if (_head) { unsigned const r = _trim_consumption(q); @@ -148,12 +150,21 @@ bool Cpu_scheduler::ready_check(Share * const s1) assert(_head); ready(s1); + + if (_need_to_schedule) return _need_to_schedule; + Share * s2 = _head; - if (!s1->_claim) { return s2 == _idle; } - if (!_head_claims) { return 1; } - if (s1->_prio != s2->_prio) { return s1->_prio > s2->_prio; } - for (; s2 && s2 != s1; s2 = _share(Claim_list::next(s2))) ; - return !s2; + if (!s1->_claim) { + _need_to_schedule = s2 == _idle; + } else if (!_head_claims) { + _need_to_schedule = true; + } else if (s1->_prio != s2->_prio) { + _need_to_schedule = s1->_prio > s2->_prio; + } else { + for (; s2 && s2 != s1; s2 = _share(Claim_list::next(s2))) ; + _need_to_schedule = !s2; + } + return _need_to_schedule; } @@ -161,6 +172,8 @@ void Cpu_scheduler::ready(Share * const s) { assert(!s->_ready && s != _idle); + _need_to_schedule = true; + s->_ready = 1; s->_fill = _fill; _fills.insert_tail(s); @@ -174,6 +187,9 @@ void Cpu_scheduler::ready(Share * const s) void Cpu_scheduler::unready(Share * const s) { assert(s->_ready && s != _idle); + + _need_to_schedule = true; + s->_ready = 0; _fills.remove(s); if (!s->_quota) { return; } @@ -182,13 +198,18 @@ void Cpu_scheduler::unready(Share * const s) } -void Cpu_scheduler::yield() { _head_yields = 1; } +void Cpu_scheduler::yield() +{ + _head_yields = true; + _need_to_schedule = true; +} void Cpu_scheduler::remove(Share * const s) { assert(s != _idle); + _need_to_schedule = true; if (s == _head) _head = nullptr; if (s->_ready) { _fills.remove(s); } if (!s->_quota) { return; } @@ -200,6 +221,7 @@ void Cpu_scheduler::remove(Share * const s) void Cpu_scheduler::insert(Share * const s) { assert(!s->_ready); + _need_to_schedule = true; if (!s->_quota) { return; } s->_claim = s->_quota; _ucl[s->_prio].insert_head(s); @@ -217,5 +239,5 @@ void Cpu_scheduler::quota(Share * const s, unsigned const q) Cpu_scheduler::Cpu_scheduler(Share * const i, unsigned const q, unsigned const f) -: _idle(i), _head_yields(0), _quota(q), _residual(q), _fill(f) +: _idle(i), _quota(q), _residual(q), _fill(f) { _set_head(i, f, 0); } diff --git a/repos/base-hw/src/core/kernel/cpu_scheduler.h b/repos/base-hw/src/core/kernel/cpu_scheduler.h index 39ce8c2575..8d53bc0d2a 100644 --- a/repos/base-hw/src/core/kernel/cpu_scheduler.h +++ b/repos/base-hw/src/core/kernel/cpu_scheduler.h @@ -128,10 +128,11 @@ class Kernel::Cpu_scheduler Share * _head = nullptr; unsigned _head_quota = 0; bool _head_claims = false; - bool _head_yields; + bool _head_yields = false; unsigned const _quota; unsigned _residual; unsigned const _fill; + bool _need_to_schedule { true }; template void _for_each_prio(F f) { for (signed p = Prio::MAX; p > Prio::MIN - 1; p--) { f(p); } } @@ -179,6 +180,9 @@ class Kernel::Cpu_scheduler */ Cpu_scheduler(Share * const i, unsigned const q, unsigned const f); + bool need_to_schedule() { return _need_to_schedule; } + void timeout() { _need_to_schedule = true; } + /** * Update head according to the consumption of quota 'q' */ diff --git a/repos/base-hw/src/core/kernel/timer.cc b/repos/base-hw/src/core/kernel/timer.cc index 2cba311d13..d9f26e0dff 100644 --- a/repos/base-hw/src/core/kernel/timer.cc +++ b/repos/base-hw/src/core/kernel/timer.cc @@ -12,6 +12,7 @@ */ /* Core includes */ +#include #include #include #include @@ -19,6 +20,13 @@ using namespace Kernel; +void Timer::Irq::occurred() { _cpu.scheduler().timeout(); } + + +Timer::Irq::Irq(unsigned id, Cpu &cpu) +: Kernel::Irq(id, cpu.irq_pool()), _cpu(cpu) {} + + time_t Timer::timeout_age_us(Timeout const * const timeout) const { time_t const age = (time_t)_time - timeout->_start; @@ -131,7 +139,8 @@ void Timer::process_timeouts() } -Timer::Timer(unsigned cpu_id) : _cpu_id(cpu_id), _driver(cpu_id) +Timer::Timer(Cpu & cpu) +: _driver(cpu.id()), _irq(interrupt_id(), cpu) { /* * The timer frequency should allow a good accuracy on the smallest diff --git a/repos/base-hw/src/core/kernel/timer.h b/repos/base-hw/src/core/kernel/timer.h index 3518244d75..8ea8c70043 100644 --- a/repos/base-hw/src/core/kernel/timer.h +++ b/repos/base-hw/src/core/kernel/timer.h @@ -16,6 +16,7 @@ /* base-hw includes */ #include +#include /* Genode includes */ #include @@ -25,6 +26,7 @@ namespace Kernel { + class Cpu; class Timeout; class Timer; } @@ -61,10 +63,23 @@ class Kernel::Timer { private: + class Irq : private Kernel::Irq + { + private: + + Cpu & _cpu; + + public: + + Irq(unsigned id, Cpu & cpu); + + void occurred() override; + }; + using Driver = Timer_driver; - unsigned const _cpu_id; Driver _driver; + Irq _irq; time_t _time = 0; bool _time_period = false; Genode::List _timeout_list[2]; @@ -82,11 +97,12 @@ class Kernel::Timer public: - Timer(unsigned cpu_id); + Timer(Cpu & cpu); void schedule_timeout(); time_t update_time(); + void process_timeouts(); void set_timeout(Timeout * const timeout, time_t const duration); diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc index aff818d821..c0be066547 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc @@ -21,12 +21,15 @@ using namespace Kernel; void Thread::Pd_update::execute() {} -void Thread::exception(Cpu&) +void Thread::exception(Cpu & cpu) { using Context = Genode::Cpu::Context; - if (regs->is_irq()) + if (regs->is_irq()) { + /* there are only cpu-local timer interrupts right now */ + cpu.interrupt(5); return; + } switch(regs->cpu_exception) { case Context::ECALL_FROM_USER: