From ef7c0c9fb1a02cced5456cda70624d7281cada5d Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Fri, 11 Apr 2025 12:45:16 +0200 Subject: [PATCH] fixup "hw: sanitize scheduler, cpu, and timer interplay" (scheduler unit test) --- .../src/test/cpu_scheduler/kernel/timer.h | 58 +++++++++++++++++++ repos/base-hw/src/test/cpu_scheduler/main.cc | 35 ++++++----- .../base-hw/src/test/cpu_scheduler/target.mk | 2 +- 3 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 repos/base-hw/src/test/cpu_scheduler/kernel/timer.h diff --git a/repos/base-hw/src/test/cpu_scheduler/kernel/timer.h b/repos/base-hw/src/test/cpu_scheduler/kernel/timer.h new file mode 100644 index 0000000000..b5e9f869ca --- /dev/null +++ b/repos/base-hw/src/test/cpu_scheduler/kernel/timer.h @@ -0,0 +1,58 @@ +/* + * \brief A timer dummy class for test-purposes + * \author Stefan Kalkowski + * \date 2025-04-11 + */ + +/* + * Copyright (C) 2025 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__KERNEL__TIMER_H_ +#define _CORE__KERNEL__TIMER_H_ + +#include + +namespace Kernel { + class Timeout; + struct Timer; +} + + +struct Kernel::Timeout +{ + virtual void timeout_triggered() {} + virtual ~Timeout() { } +}; + + +struct Kernel::Timer +{ + time_t _time { 0 }; + Timeout *_timeout { nullptr }; + time_t _next_timeout { 0 }; + + time_t time() { return _time; } + + time_t schedule_timeout() { return 0; } /* dummy unneeded */ + + void set_timeout(Timeout * const timeout, time_t const duration) + { + _next_timeout = _time + duration; + _timeout = timeout; + } + + void add_time(time_t const duration) + { + _time += duration; + if (_timeout && _next_timeout <= _time) { + _timeout->timeout_triggered(); + _timeout = nullptr; + } + } +}; + +#endif diff --git a/repos/base-hw/src/test/cpu_scheduler/main.cc b/repos/base-hw/src/test/cpu_scheduler/main.cc index 1eba863af6..e5696827ab 100644 --- a/repos/base-hw/src/test/cpu_scheduler/main.cc +++ b/repos/base-hw/src/test/cpu_scheduler/main.cc @@ -84,8 +84,8 @@ class Scheduler_test::Main Env &_env; Context _idle_context { 0, 0, (unsigned)IDLE_SHARE_ID }; Constructible _contexts[MAX_NR_OF_SHARES] { }; - time_t _current_time { 0 }; - Scheduler _scheduler; + Timer _timer {}; + Scheduler _scheduler; unsigned _id_of_context(Context const &c) const { @@ -182,11 +182,16 @@ class Scheduler_test::Main void _update_current_and_check(unsigned const consumed_time, unsigned const expected_round_time, unsigned const expected_current_id, - unsigned const expected_current_time_left, + unsigned const, unsigned const line_nr) { - _current_time += consumed_time; - _scheduler.update(_current_time); + _timer.add_time(consumed_time); + + /* we've to force it's no up-to-date, otherwise update has no effect */ + if (_scheduler._state == Scheduler::UP_TO_DATE) + _scheduler._state = Scheduler::OUT_OF_DATE; + + _scheduler.update(); unsigned const round_time { _scheduler._super_period_length - _scheduler._super_period_left }; @@ -196,7 +201,6 @@ class Scheduler_test::Main _env.parent().exit(-1); } Context ¤t { cast(_scheduler.current()) }; - unsigned const current_time_left { _scheduler.current_time_left() }; if (¤t != &_context(expected_current_id)) { error("wrong share ", _id_of_context(current), " in line ", @@ -204,11 +208,6 @@ class Scheduler_test::Main _env.parent().exit(-1); } - if (current_time_left != expected_current_time_left) { - - error("wrong quota ", current_time_left, " in line ", line_nr); - _env.parent().exit(-1); - } } void _set_context_ready_and_check(unsigned const share_id, @@ -216,10 +215,10 @@ class Scheduler_test::Main unsigned const line_nr) { _scheduler.ready(_context(share_id)); - if (_scheduler.need_to_schedule() != expect_current_outdated) { + if (_scheduler.need_to_update() != expect_current_outdated) { error("wrong check result ", - _scheduler.need_to_schedule(), " in line ", line_nr); + _scheduler.need_to_update(), " in line ", line_nr); _env.parent().exit(-1); } @@ -260,13 +259,13 @@ void Scheduler_test::Scheduler::print(Output &output) const print(output, "(\n"); print(output, " quota: ", _super_period_left, "/", _super_period_length, ", "); print(output, "slack: ", _slack_quota, ", "); - print(output, "need to schedule: ", need_to_schedule() ? "true" : "false", ", "); + print(output, "need to update: ", need_to_update() ? "true" : "false", ", "); print(output, "last_time: ", _last_time); if (_current != nullptr) { print(output, "\n current: ( "); - if (need_to_schedule()) { + if (need_to_update()) { print(output, "\033[31m"); } else { print(output, "\033[32m"); @@ -299,7 +298,7 @@ void Scheduler_test::Scheduler::print(Output &output) const _rpl[p].for_each([&] (Kernel::Scheduler::Context const &c) { if (&c == _current && _current->_priotized_time_left) { - if (need_to_schedule()) { + if (need_to_update()) { print(output, "\033[31m"); } else { print(output, "\033[32m"); @@ -339,7 +338,7 @@ void Scheduler_test::Scheduler::print(Output &output) const _slack_list.for_each([&] (Kernel::Scheduler::Context const &c) { if (&c == _current && !_current->_priotized_time_left) { - if (need_to_schedule()) { + if (need_to_update()) { print(output, "\033[31m"); } else { print(output, "\033[32m"); @@ -368,7 +367,7 @@ void Scheduler_test::Scheduler::print(Output &output) const Scheduler_test::Main::Main(Env &env) : _env { env }, - _scheduler { _idle_context, 1000, 100 } + _scheduler { _timer, _idle_context, 1000, 100 } { /******************** ** Round #1: Idle ** diff --git a/repos/base-hw/src/test/cpu_scheduler/target.mk b/repos/base-hw/src/test/cpu_scheduler/target.mk index c36ac734fc..fe184c5d0b 100644 --- a/repos/base-hw/src/test/cpu_scheduler/target.mk +++ b/repos/base-hw/src/test/cpu_scheduler/target.mk @@ -6,7 +6,7 @@ TARGET = test-cpu_scheduler SRC_CC = main.cc scheduler.cc -INC_DIR += $(REP_DIR)/src/core $(REP_DIR)/src/include $(BASE_DIR)/src/include +INC_DIR += $(PRG_DIR) $(REP_DIR)/src/core $(REP_DIR)/src/include $(BASE_DIR)/src/include LIBS = base REP_INC_DIR += src/core/include