mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 20:05:54 +00:00
hw: schedule on demand (Fix #3157)
This commit is contained in:
parent
a58fcc3b1e
commit
2ecf1d887b
@ -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(); }
|
||||
|
||||
|
@ -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 {};
|
||||
|
@ -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); }
|
||||
|
@ -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 <typename F> 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'
|
||||
*/
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
/* Core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/timer.h>
|
||||
#include <kernel/configuration.h>
|
||||
#include <hw/assert.h>
|
||||
@ -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
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
#include <kernel/irq.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
@ -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> _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);
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user