From 8e2c95e5e4194f804d2ddd2e0381b9ce85e2b412 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Mon, 5 Feb 2024 15:53:08 +0100 Subject: [PATCH] hw: replace double_list implementation Replace double linked list by normal Genode::List with an additional pointer to last list member to efficiently handle the scheduler share lists. Moreover, move it into the private part of the Cpu_scheduler class, the only scope where it is used anymore. Ref genodelabs/genode#5115 --- repos/base-hw/run/double_list.run | 56 ----- .../base-hw/src/core/kernel/cpu_scheduler.cc | 19 +- repos/base-hw/src/core/kernel/cpu_scheduler.h | 112 +++++++-- repos/base-hw/src/core/kernel/double_list.h | 192 --------------- repos/base-hw/src/test/cpu_scheduler/main.cc | 16 +- repos/base-hw/src/test/double_list/target.mk | 12 - repos/base-hw/src/test/double_list/test.cc | 222 ------------------ 7 files changed, 103 insertions(+), 526 deletions(-) delete mode 100644 repos/base-hw/run/double_list.run delete mode 100644 repos/base-hw/src/core/kernel/double_list.h delete mode 100644 repos/base-hw/src/test/double_list/target.mk delete mode 100644 repos/base-hw/src/test/double_list/test.cc diff --git a/repos/base-hw/run/double_list.run b/repos/base-hw/run/double_list.run deleted file mode 100644 index 56dc6176f3..0000000000 --- a/repos/base-hw/run/double_list.run +++ /dev/null @@ -1,56 +0,0 @@ -build { core init lib/ld test/double_list } - -create_boot_directory - -install_config { - - - - - - - - - - - - - - - -} - -build_boot_image [build_artifacts] - -append qemu_args " -nographic" - -run_genode_until "done.*\n" 10 - -grep_output {\[init -> test-double_list\]} -compare_output_to { - [init -> test-double_list] print each - [init -> test-double_list] print each - [init -> test-double_list] 1 - [init -> test-double_list] print each - [init -> test-double_list] 3 - [init -> test-double_list] 2 - [init -> test-double_list] 5 - [init -> test-double_list] 7 - [init -> test-double_list] 6 - [init -> test-double_list] 4 - [init -> test-double_list] 1 - [init -> test-double_list] print each - [init -> test-double_list] 8 - [init -> test-double_list] 9 - [init -> test-double_list] 2 - [init -> test-double_list] 5 - [init -> test-double_list] 1 - [init -> test-double_list] 7 - [init -> test-double_list] 6 - [init -> test-double_list] 4 - [init -> test-double_list] 3 - [init -> test-double_list] print each - [init -> test-double_list] 7 - [init -> test-double_list] 8 - [init -> test-double_list] done -} diff --git a/repos/base-hw/src/core/kernel/cpu_scheduler.cc b/repos/base-hw/src/core/kernel/cpu_scheduler.cc index 03ef6b50ef..8cf4ab3452 100644 --- a/repos/base-hw/src/core/kernel/cpu_scheduler.cc +++ b/repos/base-hw/src/core/kernel/cpu_scheduler.cc @@ -82,7 +82,7 @@ void Cpu_scheduler::_head_claimed(unsigned const r) void Cpu_scheduler::_head_filled(unsigned const r) { - if (_fills.head() != &_head->_fill_item) + if (_fills.head() != _head) return; if (r) @@ -98,17 +98,15 @@ bool Cpu_scheduler::_claim_for_head() { bool result { false }; _for_each_prio([&] (Cpu_priority const p, bool &cancel_for_each_prio) { - Double_list_item *const item { _rcl[p].head() }; + Cpu_share* const share = _rcl[p].head(); - if (!item) + if (!share) return; - Cpu_share &share { item->payload() }; - - if (!share._claim) + if (!share->_claim) return; - _set_head(share, share._claim, 1); + _set_head(*share, share->_claim, 1); result = true; cancel_for_each_prio = true; }); @@ -118,12 +116,11 @@ bool Cpu_scheduler::_claim_for_head() bool Cpu_scheduler::_fill_for_head() { - Double_list_item *const item { _fills.head() }; - if (!item) + Cpu_share *const share = _fills.head(); + if (!share) return false; - Share &share = item->payload(); - _set_head(share, share._fill, 0); + _set_head(*share, share->_fill, 0); return true; } diff --git a/repos/base-hw/src/core/kernel/cpu_scheduler.h b/repos/base-hw/src/core/kernel/cpu_scheduler.h index d5c2e9934d..b6e1ae83b3 100644 --- a/repos/base-hw/src/core/kernel/cpu_scheduler.h +++ b/repos/base-hw/src/core/kernel/cpu_scheduler.h @@ -1,6 +1,7 @@ /* * \brief Schedules CPU shares for the execution time of a CPU * \author Martin Stein + * \author Stefan Kalkowski * \date 2014-10-09 */ @@ -16,9 +17,9 @@ /* core includes */ #include +#include #include #include -#include namespace Kernel { @@ -90,13 +91,15 @@ class Kernel::Cpu_share private: - Double_list_item _fill_item { *this }; - Double_list_item _claim_item { *this }; - Cpu_priority const _prio; - unsigned _quota; - unsigned _claim; - unsigned _fill { 0 }; - bool _ready { false }; + using List_element = Genode::List_element; + + List_element _fill_item { this }; + List_element _claim_item { this }; + Cpu_priority const _prio; + unsigned _quota; + unsigned _claim; + unsigned _fill { 0 }; + bool _ready { false }; public: @@ -123,22 +126,89 @@ class Kernel::Cpu_scheduler private: + class Share_list + { + private: + + using List_element = Genode::List_element; + + Genode::List _list {}; + List_element *_last { nullptr }; + + public: + + template void for_each(F const &fn) + { + for (List_element * le = _list.first(); le; le = le->next()) + fn(*le->object()); + } + + template void for_each(F const &fn) const + { + for (List_element const * le = _list.first(); le; + le = le->next()) fn(*le->object()); + } + + Cpu_share* head() const { + return _list.first() ? _list.first()->object() : nullptr; } + + void insert_head(List_element * const le) + { + _list.insert(le); + if (!_last) _last = le; + } + + void insert_tail(List_element * const le) + { + _list.insert(le, _last); + _last = le; + } + + void remove(List_element * const le) + { + _list.remove(le); + + if (_last != le) + return; + + _last = nullptr; + for (List_element * le = _list.first(); le; le = le->next()) + _last = le; + } + + + void to_tail(List_element * const le) + { + remove(le); + insert_tail(le); + } + + void to_head(List_element * const le) + { + remove(le); + insert_head(le); + } + + void head_to_tail() { + to_tail(_list.first()); } + }; + typedef Cpu_share Share; typedef Cpu_priority Prio; - Double_list _rcl[Prio::max() + 1]; /* ready claims */ - Double_list _ucl[Prio::max() + 1]; /* unready claims */ - Double_list _fills { }; /* ready fills */ - Share &_idle; - Share *_head = nullptr; - unsigned _head_quota = 0; - bool _head_claims = false; - bool _head_yields = false; - unsigned const _quota; - unsigned _residual; - unsigned const _fill; - bool _need_to_schedule { true }; - time_t _last_time { 0 }; + Share_list _rcl[Prio::max() + 1]; /* ready claims */ + Share_list _ucl[Prio::max() + 1]; /* unready claims */ + Share_list _fills { }; /* ready fills */ + Share &_idle; + Share *_head = nullptr; + unsigned _head_quota = 0; + bool _head_claims = false; + bool _head_yields = false; + unsigned const _quota; + unsigned _residual; + unsigned const _fill; + bool _need_to_schedule { true }; + time_t _last_time { 0 }; template void _for_each_prio(F f) { diff --git a/repos/base-hw/src/core/kernel/double_list.h b/repos/base-hw/src/core/kernel/double_list.h deleted file mode 100644 index ec580f9823..0000000000 --- a/repos/base-hw/src/core/kernel/double_list.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * \brief List of double connected items - * \author Martin Stein - * \date 2012-11-30 - */ - -/* - * Copyright (C) 2012-2017 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__DOUBLE_LIST_H_ -#define _CORE__KERNEL__DOUBLE_LIST_H_ - -namespace Kernel { - - /** - * Ability to be an item in a double connected list - */ - template - class Double_list_item; - - /** - * List of double connected items - */ - template - class Double_list; -} - - -template -class Kernel::Double_list_item -{ - friend class Double_list; - - private: - - Double_list_item * _next = nullptr; - Double_list_item * _prev = nullptr; - T & _payload; - - public: - - Double_list_item(T &payload) : _payload(payload) { } - - T &payload() { return _payload; } -}; - - -template -class Kernel::Double_list -{ - private: - - typedef Double_list_item Item; - - Item * _head; - Item * _tail; - - void _connect_neighbors(Item * const i) - { - i->_prev->_next = i->_next; - i->_next->_prev = i->_prev; - } - - void _to_tail(Item * const i) - { - if (i == _tail) { return; } - _connect_neighbors(i); - i->_prev = _tail; - i->_next = 0; - _tail->_next = i; - _tail = i; - } - - void _to_head(Item * const i) - { - if (i == _head) - return; - - _connect_neighbors(i); - i->_next = _head; - i->_prev = 0; - _head->_prev = i; - _head = i; - } - - void _tail_to_head() - { - if (_tail == 0 || _tail == _head) - return; - - _tail->_next = _head; - _head->_prev = _tail; - _tail = _tail->_prev; - _tail->_next = 0; - _head = _head->_prev; - _head->_prev = 0; - } - - public: - - /** - * Construct empty list - */ - Double_list() : _head(0), _tail(0) { } - - /** - * Move item 'i' from its current list position to the tail - */ - void to_tail(Item * const i) - { - if (i == _head) { head_to_tail(); } - else { _to_tail(i); } - } - - void to_head(Item * const i) - { - if (i == _tail) - _tail_to_head(); - else - _to_head(i); - } - - /** - * Insert item 'i' as new tail into list - */ - void insert_tail(Item * const i) - { - if (_tail) { _tail->_next = i; } - else { _head = i; } - i->_prev = _tail; - i->_next = 0; - _tail = i; - } - - /** - * Insert item 'i' as new head into list - */ - void insert_head(Item * const i) - { - if (_head) { _head->_prev = i; } - else { _tail = i; } - i->_next = _head; - i->_prev = 0; - _head = i; - } - - /** - * Remove item 'i' from list - */ - void remove(Item * const i) - { - if (i == _tail) { _tail = i->_prev; } - else { i->_next->_prev = i->_prev; } - if (i == _head) { _head = i->_next; } - else { i->_prev->_next = i->_next; } - } - - /** - * Move head item of list to tail position - */ - void head_to_tail() - { - if (!_head || _head == _tail) - return; - - _head->_prev = _tail; - _tail->_next = _head; - _head = _head->_next; - _head->_prev = 0; - _tail = _tail->_next; - _tail->_next = 0; - } - - /** - * Call function 'f' of type 'void (Item *)' for each item in the list - */ - template void for_each(F f) { - for (Item * i = _head; i; i = i->_next) { f(i->payload()); } } - - /* - * Accessors - */ - - Item * head() const { return _head; } - static Item * next(Item * const i) { return i->_next; } -}; - -#endif /* _CORE__KERNEL__DOUBLE_LIST_H_ */ diff --git a/repos/base-hw/src/test/cpu_scheduler/main.cc b/repos/base-hw/src/test/cpu_scheduler/main.cc index d6c8e87d00..1b2829d0e4 100644 --- a/repos/base-hw/src/test/cpu_scheduler/main.cc +++ b/repos/base-hw/src/test/cpu_scheduler/main.cc @@ -27,11 +27,10 @@ namespace Cpu_scheduler_test { class Cpu_scheduler; class Main; + using Share_list = List>; static Cpu_share &cast(Kernel::Cpu_share &share); static Cpu_share const &cast(Kernel::Cpu_share const &share); - - static Double_list &cast(Double_list const &list); } @@ -255,13 +254,6 @@ Cpu_scheduler_test::cast(Kernel::Cpu_share const &share) } -static Double_list & -Cpu_scheduler_test::cast(Double_list const &list) -{ - return *const_cast *>(&list); -} - - /*************************************** ** Cpu_scheduler_test::Cpu_scheduler ** ***************************************/ @@ -308,7 +300,7 @@ void Cpu_scheduler_test::Cpu_scheduler::print(Output &output) const print(output, " ready: "); bool first_share { true }; - cast(_rcl[prio]).for_each([&] (Kernel::Cpu_share const &share) { + _rcl[prio].for_each([&] (Kernel::Cpu_share const &share) { if (&share == _head && _head_claims) { if (_need_to_schedule) { @@ -331,7 +323,7 @@ void Cpu_scheduler_test::Cpu_scheduler::print(Output &output) const print(output, " unready: "); bool first_share { true }; - cast(_ucl[prio]).for_each([&] (Kernel::Cpu_share const &share) { + _ucl[prio].for_each([&] (Kernel::Cpu_share const &share) { print( output, first_share ? "" : ", ", cast(share).label() , "-", @@ -348,7 +340,7 @@ void Cpu_scheduler_test::Cpu_scheduler::print(Output &output) const print(output, "\n fills: "); bool first_share { true }; - cast(_fills).for_each([&] (Kernel::Cpu_share const &share) { + _fills.for_each([&] (Kernel::Cpu_share const &share) { if (&share == _head && !_head_claims) { if (_need_to_schedule) { diff --git a/repos/base-hw/src/test/double_list/target.mk b/repos/base-hw/src/test/double_list/target.mk deleted file mode 100644 index 5fc7acf945..0000000000 --- a/repos/base-hw/src/test/double_list/target.mk +++ /dev/null @@ -1,12 +0,0 @@ -# -# \brief Build config for a core that tests its double-list implementation -# \author Martin Stein -# \date 2011-12-16 -# - -TARGET = test-double_list -INC_DIR = $(REP_DIR)/src/core -SRC_CC = test.cc -LIBS = base - -vpath double_list.cc $(REP_DIR)/src/core/kernel diff --git a/repos/base-hw/src/test/double_list/test.cc b/repos/base-hw/src/test/double_list/test.cc deleted file mode 100644 index ae88aeb153..0000000000 --- a/repos/base-hw/src/test/double_list/test.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* - * \brief Test double-list implementation of the kernel - * \author Martin Stein - * \date 2014-09-30 - */ - -/* - * Copyright (C) 2014-2017 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. - */ - -/* base includes */ -#include -#include -#include - -/* core includes */ -#include - - -/* - * Utilities - */ - -using Genode::size_t; -using Kernel::Double_list; -using Kernel::Double_list_item; - - -struct Item_load { char volatile x = 0, y = 0, z = 0; }; - - -struct Item : Item_load, Double_list_item -{ - unsigned _id; - - Item(unsigned const id) : Double_list_item(*this), _id(id) { x = 1; y = 2; z = 3; } - - void iteration() { Genode::log(_id); } -}; - - -struct Data -{ - static constexpr unsigned nr_of_items = 9; - - Double_list list { }; - char items[nr_of_items][sizeof(Item)]; - - Data() - { - for (unsigned i = 0; i < nr_of_items; i++) { - Genode::construct_at(&items[i], i + 1); } - } -}; - - -Data * data() -{ - static Data d; - return &d; -} - - -void done() -{ - Genode::log("done"); - while (1) ; -} - - -void check(unsigned i1, unsigned l) -{ - Double_list_item * const li2 = data()->list.head(); - if (li2) { - Item * const i2 = &li2->payload(); - if (i1) { - if(i1 == i2->_id) { return; } - Genode::log("head ", i2->_id, " in line ", l); - done(); - } else { - Genode::log("non-empty ", i2->_id, " in line ", l); - done(); - } - } else if (i1) { - Genode::log("empty in line ", l); - done(); - } -} - - -void print_each() -{ - Genode::log("print each"); - data()->list.for_each([] (Item &i) { i.iteration(); }); -} - - -Item * item(unsigned const i) { - return reinterpret_cast(&data()->items[i - 1]); } - - -/* - * Shortcuts for all basic operations that the test consists of - */ - -#define C(i) check(i, __LINE__); -#define T(i) data()->list.insert_tail(item(i)); -#define H(i) data()->list.insert_head(item(i)); -#define R(i) data()->list.remove(item(i)); -#define B(i) data()->list.to_tail(item(i)); -#define P print_each(); -#define N data()->list.head_to_tail(); - - -/** - * Main routine - */ -void Component::construct(Genode::Env &) -{ - /* - * Step-by-step testing - * - * Every line in this test is structured according to the scheme - * ' C(i) ' where the symbols are defined as follows: - * - * ops Operations that affect the list structure. These are: - * - * T(i) insert the item with ID 'i' as tail - * H(i) insert the item with ID 'i' as head - * R(i) remove the item with ID 'i' - * B(i) move the item with ID 'i' to the tail - * N move the head to the tail - * P print IDs of the items in the list in their list order - * - * C(i) check if the item with ID 'i' is head - * - * doc Documents the expected list content for the point after the - * operations in the corresponding line. - * - * If any check in a line fails, the test prematurely stops and prints out - * where and why it has stopped. - */ - - C(0) /* */ - N C(0) /* */ - P C(0) /* */ - T(1) C(1) /* 1 */ - N C(1) /* 1 */ - P N C(1) /* 1 */ - B(1) C(1) /* 1 */ - N C(1) /* 1 */ - R(1) C(0) /* */ - N C(0) /* */ - N C(0) /* */ - H(2) C(2) /* 2 */ - N C(2) /* 2 */ - N C(2) /* 2 */ - T(3) C(2) /* 2 3 */ - N C(3) /* 3 2 */ - B(2) C(3) /* 3 2 */ - N C(2) /* 2 3 */ - H(4) C(4) /* 4 2 3 */ - N C(2) /* 2 3 4 */ - N C(3) /* 3 4 2 */ - N C(4) /* 4 2 3 */ - R(4) N C(3) /* 3 2 */ - N C(2) /* 2 3 */ - T(1) C(2) /* 2 3 1 */ - N C(3) /* 3 1 2 */ - N C(1) /* 1 2 3 */ - N C(2) /* 2 3 1 */ - N C(3) /* 3 1 2 */ - R(1) C(3) /* 3 2 */ - N C(2) /* 2 3 */ - N C(3) /* 3 2 */ - B(3) C(2) /* 2 3 */ - T(4) T(1) C(2) /* 2 3 4 1 */ - N N C(4) /* 4 1 2 3 */ - N C(1) /* 1 2 3 4 */ - N N C(3) /* 3 4 1 2 */ - R(2) C(3) /* 3 4 1 */ - R(3) C(4) /* 4 1 */ - N C(1) /* 1 4 */ - N N C(1) /* 1 4 */ - T(3) T(2) C(1) /* 1 4 3 2 */ - T(5) N C(4) /* 4 3 2 5 1 */ - T(7) H(6) C(6) /* 6 4 3 2 5 1 7 */ - N C(4) /* 4 3 2 5 1 7 6 */ - B(4) C(3) /* 3 2 5 1 7 6 4 */ - B(4) N N C(5) /* 5 1 7 6 4 3 2 */ - N B(7) N C(6) /* 6 4 3 2 5 7 1*/ - N N B(1) C(3) /* 3 2 5 7 6 4 1 */ - P C(3) /* 3 2 5 7 6 4 1 */ - R(4) H(4) C(4) /* 4 3 2 5 7 6 1 */ - B(7) B(6) C(4) /* 4 3 2 5 1 7 6 */ - N N N C(5) /* 5 1 7 6 4 3 2 */ - N N N C(6) /* 6 4 3 2 5 1 7 */ - N N N C(2) /* 2 5 1 7 6 4 3 */ - T(9) N N C(1) /* 1 7 6 4 3 9 2 5 */ - N N N N C(3) /* 3 9 2 5 1 7 6 4 */ - N N N N C(1) /* 1 7 6 4 3 9 2 5 */ - N N N C(4) /* 4 3 9 2 5 1 7 6 */ - N N C(9) /* 9 2 5 1 7 6 4 3 */ - H(8) P C(8) /* 8 9 2 5 1 7 6 4 3 */ - R(8) C(9) /* 9 2 5 1 7 6 4 3 */ - R(9) C(2) /* 2 5 1 7 6 4 3 */ - R(1) N N C(7) /* 7 6 4 3 2 5 */ - N R(6) N C(3) /* 3 2 5 7 4 */ - T(8) R(3) C(2) /* 2 5 7 4 8 */ - N N R(5) C(7) /* 7 4 8 2 */ - R(2) R(4) C(7) /* 7 8 */ - N C(8) /* 8 7 */ - N P C(7) /* 7 8 */ - R(7) C(8) /* 7 8 */ - R(8) C(0) /* */ - C(0) /* */ - - done(); -}