diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index bf2d320cfe..80260a35f3 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -68,14 +68,6 @@ void Cpu_context::_interrupt(Irq::Pool &user_irq_pool) } -void Cpu_context::affinity(Cpu &cpu) -{ - _cpu().scheduler().remove(*this); - _cpu_ptr = &cpu; - _cpu().scheduler().insert(*this); -} - - void Cpu_context::quota(unsigned const q) { _cpu().scheduler().quota(*this, q); @@ -122,7 +114,7 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a void Cpu::assign(Context &context) { _scheduler.ready(static_cast(context)); - if (_id != executing_id() && _scheduler.need_to_schedule()) + if (_id != executing_id() && _scheduler.need_to_update()) trigger_ip_interrupt(); } @@ -139,22 +131,12 @@ bool Cpu::handle_if_cpu_local_interrupt(unsigned const irq_id) } -Cpu::Context & Cpu::schedule_next_context(Context &last) +Cpu::Context & Cpu::schedule_next_context() { if (_state == SUSPEND || _state == HALT) return _halt_job; - /* update schedule if necessary */ - if (_scheduler.need_to_schedule()) { - _timer.process_timeouts(); - _scheduler.update(_timer.time()); - time_t t = _scheduler.current_time_left(); - _timer.set_timeout(&_timeout, t); - time_t duration = _timer.schedule_timeout(); - last.update_execution_time(duration); - } - - /* return current context */ + _scheduler.update(); return current_context(); } @@ -182,9 +164,9 @@ Cpu::Cpu(unsigned const id, _id { id }, _pic { global_irq_ctrl }, _timer { *this }, - _scheduler { _idle, _quota(), _fill() }, _idle { addr_space_id_alloc, user_irq_pool, cpu_pool, *this, core_pd }, + _scheduler { _timer, _idle, _quota(), _fill() }, _ipi_irq { *this }, _global_work_list { cpu_pool.work_list() } { diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h index 2314322dd8..4bf2811f8a 100644 --- a/repos/base-hw/src/core/kernel/cpu.h +++ b/repos/base-hw/src/core/kernel/cpu.h @@ -99,10 +99,9 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool, State _state { RUN }; unsigned const _id; Board::Pic _pic; - Timeout _timeout {}; Timer _timer; - Scheduler _scheduler; Idle_thread _idle; + Scheduler _scheduler; Ipi _ipi_irq; Inter_processor_work_list &_global_work_list; @@ -150,7 +149,7 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool, /** * Return the context that should be executed next */ - Context& schedule_next_context(Context &last); + Context& schedule_next_context(); Board::Pic & pic() { return _pic; } Timer & timer() { return _timer; } diff --git a/repos/base-hw/src/core/kernel/cpu_context.h b/repos/base-hw/src/core/kernel/cpu_context.h index 29dcc687e8..9a5bf1749f 100644 --- a/repos/base-hw/src/core/kernel/cpu_context.h +++ b/repos/base-hw/src/core/kernel/cpu_context.h @@ -35,8 +35,7 @@ class Kernel::Cpu_context : private Scheduler::Context friend class Cpu; - time_t _execution_time { 0 }; - Cpu *_cpu_ptr; + Cpu *_cpu_ptr; /* * Noncopyable @@ -83,25 +82,12 @@ class Kernel::Cpu_context : private Scheduler::Context virtual ~Cpu_context(); - /** - * Link context to CPU 'cpu' - */ - void affinity(Cpu &cpu); - /** * Set CPU quota of the context to 'q' */ void quota(unsigned const q); - /** - * Update total execution time - */ - void update_execution_time(time_t duration) { _execution_time += duration; } - - /** - * Return total execution time - */ - time_t execution_time() const { return _execution_time; } + using Scheduler::Context::execution_time; /** * Handle exception that occured during execution of this context diff --git a/repos/base-hw/src/core/kernel/main.cc b/repos/base-hw/src/core/kernel/main.cc index a88e15ce6b..e9e8a9f3fd 100644 --- a/repos/base-hw/src/core/kernel/main.cc +++ b/repos/base-hw/src/core/kernel/main.cc @@ -70,7 +70,7 @@ void Kernel::Main::_handle_kernel_entry(Genode::Cpu_state *state) Cpu &cpu = _cpu_pool.cpu(Cpu::executing_id()); Cpu::Context &recent = cpu.current_context(); if (state) recent.exception(*state); - context = &cpu.schedule_next_context(recent); + context = &cpu.schedule_next_context(); }, [&] () { _cpu_pool.cpu(Cpu::executing_id()).panic(*state); }); diff --git a/repos/base-hw/src/core/kernel/scheduler.cc b/repos/base-hw/src/core/kernel/scheduler.cc index da8d8accb2..e9fd8d1d2a 100644 --- a/repos/base-hw/src/core/kernel/scheduler.cc +++ b/repos/base-hw/src/core/kernel/scheduler.cc @@ -51,6 +51,13 @@ Scheduler::Context::~Context() } +void Scheduler::Timeout::timeout_triggered() +{ + if (_scheduler._state == UP_TO_DATE) + _scheduler._state = OUT_OF_DATE; +} + + void Scheduler::_consumed(unsigned const time) { if (_super_period_left > time) { @@ -149,15 +156,21 @@ bool Scheduler::_schedule_slack() } -void Scheduler::update(time_t time) +void Scheduler::update() { using namespace Genode; + if (!need_to_update()) + return; + + time_t time = _timer.time(); unsigned const duration = min(min((unsigned)(time-_last_time), _current_quantum), _super_period_left); _last_time = time; + if (_current) _current->_execution_time += duration; + /* do not detract the quota of idle or removed context */ if (_current && _current != &_idle) { unsigned const r = (_state != YIELD) ? _current_quantum - duration : 0; @@ -169,13 +182,14 @@ void Scheduler::update(time_t time) _state = UP_TO_DATE; - if (_schedule_priotized()) - return; + if (!_schedule_priotized()) + if (!_schedule_slack()) + _set_current(_idle, _slack_quota); - if (_schedule_slack()) - return; + _timer.set_timeout(&_timeout, + Genode::min(_current_quantum, _super_period_left)); + _timer.schedule_timeout(); - _set_current(_idle, _slack_quota); } @@ -298,18 +312,20 @@ Scheduler::Context& Scheduler::current() { if (!_current) { Genode::error("attempt to access invalid scheduler's current context"); - update(_last_time); + update(); } return *_current; } -Scheduler::Scheduler(Context &idle, +Scheduler::Scheduler(Timer &timer, + Context &idle, unsigned const super_period_length, unsigned const slack_quota) : _slack_quota(slack_quota), _super_period_length(super_period_length), + _timer(timer), _idle(idle) { _set_current(idle, slack_quota); diff --git a/repos/base-hw/src/core/kernel/scheduler.h b/repos/base-hw/src/core/kernel/scheduler.h index 4f4af83714..665f5f211a 100644 --- a/repos/base-hw/src/core/kernel/scheduler.h +++ b/repos/base-hw/src/core/kernel/scheduler.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace Kernel { class Scheduler; } @@ -79,6 +80,8 @@ class Kernel::Scheduler List _helper_list {}; Context *_destination { nullptr }; + time_t _execution_time { 0 }; + bool _ready { false }; void _reset() { _priotized_time_left = _quota; } @@ -104,6 +107,9 @@ class Kernel::Scheduler void help(Context &c); void helping_finished(); Context& helping_destination(); + + time_t execution_time() const { + return _execution_time; } }; private: @@ -174,6 +180,15 @@ class Kernel::Scheduler } }; + struct Timeout : Kernel::Timeout + { + Scheduler &_scheduler; + + Timeout(Scheduler &scheduler) : _scheduler(scheduler) {} + + virtual void timeout_triggered() override; + }; + enum State { UP_TO_DATE, OUT_OF_DATE, YIELD }; unsigned const _slack_quota; @@ -182,8 +197,11 @@ class Kernel::Scheduler unsigned _super_period_left { _super_period_length }; unsigned _current_quantum { 0 }; - time_t _last_time { 0 }; - State _state { UP_TO_DATE }; + Timer &_timer; + Timeout _timeout { *this }; + time_t _last_time { 0 }; + + State _state { UP_TO_DATE }; Context_list _rpl[cpu_priorities]; /* ready lists by priority */ Context_list _upl[cpu_priorities]; /* unready lists by priority */ @@ -206,21 +224,25 @@ class Kernel::Scheduler bool _schedule_priotized(); bool _schedule_slack(); + /** + * Noncopyable + */ + Scheduler(const Scheduler&) = delete; + Scheduler& operator=(const Scheduler&) = delete; + public: - Scheduler(Context &idle, + Scheduler(Timer &timer, + Context &idle, unsigned const super_period_length, unsigned const slack_quota); - bool need_to_schedule() const { return _state != UP_TO_DATE; } - - void timeout() { - if (_state == UP_TO_DATE) _state = OUT_OF_DATE; } + bool need_to_update() const { return _state != UP_TO_DATE; } /** - * Update state according to the current (absolute) time + * Update state */ - void update(time_t time); + void update(); /** * Set 'context' ready @@ -253,9 +275,6 @@ class Kernel::Scheduler void quota(Context &context, unsigned const quota); Context& current(); - - unsigned current_time_left() const { - return Genode::min(_current_quantum, _super_period_left); } }; #endif /* _CORE__KERNEL__SCHEDULER_H_ */ diff --git a/repos/base-hw/src/core/kernel/timer.cc b/repos/base-hw/src/core/kernel/timer.cc index 3e3bff6113..39ecf8df70 100644 --- a/repos/base-hw/src/core/kernel/timer.cc +++ b/repos/base-hw/src/core/kernel/timer.cc @@ -20,13 +20,13 @@ using namespace Kernel; -void Timer::Irq::occurred() { _cpu.scheduler().timeout(); } +void Timer::Irq::occurred() { _timer._process_timeouts(); } Timer::Irq::Irq(unsigned id, Cpu &cpu) : Kernel::Irq { id, cpu.irq_pool(), cpu.pic() }, - _cpu { cpu } + _timer { cpu.timer() } { } @@ -79,7 +79,7 @@ time_t Timer::schedule_timeout() } -void Timer::process_timeouts() +void Timer::_process_timeouts() { /* * Walk through timeouts until the first whose end time is in the future. @@ -100,7 +100,7 @@ void Timer::process_timeouts() } -Timer::Timer(Cpu & cpu) +Timer::Timer(Cpu &cpu) : _device(cpu.id()), _irq(interrupt_id(), cpu), _last_timeout_duration(_max_value()) diff --git a/repos/base-hw/src/core/kernel/timer.h b/repos/base-hw/src/core/kernel/timer.h index 920847803c..ac92d2bfca 100644 --- a/repos/base-hw/src/core/kernel/timer.h +++ b/repos/base-hw/src/core/kernel/timer.h @@ -65,11 +65,11 @@ class Kernel::Timer { private: - Cpu & _cpu; + Timer &_timer; public: - Irq(unsigned id, Cpu & cpu); + Irq(unsigned id, Cpu &cpu); void occurred() override; }; @@ -88,6 +88,8 @@ class Kernel::Timer time_t _duration() const; + void _process_timeouts(); + public: Timer(Cpu & cpu); @@ -97,8 +99,6 @@ class Kernel::Timer */ time_t schedule_timeout(); - void process_timeouts(); - void set_timeout(Timeout * const timeout, time_t const duration); time_t us_to_ticks(time_t const us) const;