diff --git a/repos/base-hw/run/double_list.run b/repos/base-hw/run/double_list.run new file mode 100644 index 0000000000..7a98b5f3ad --- /dev/null +++ b/repos/base-hw/run/double_list.run @@ -0,0 +1,31 @@ +# +# \brief Test double-list implementation of core +# \author Martin Stein +# \date 2014-09-30 +# + +# build program images +build "test/double_list" + +# create directory where the boot files are written to +create_boot_directory + +# create single boot image from the compiled program images +build_boot_image "test-double_list" test + +# configure qemu to use 64 MB RAM and avoid GUI mode +append qemu_args " -m 64 -nographic" + +# execute the test in qemu if the targeted platform is supported +run_genode_until "done.*\n" 10 + +# check the output +grep_output {\[test\]} +compare_output_to { + [test] print each + [test] print each 1 + [test] print each 3 2 5 7 6 4 1 + [test] print each 8 9 2 5 1 7 6 4 3 + [test] print each 7 8 + [test] done +} diff --git a/repos/base-hw/src/core/include/kernel/double_list.h b/repos/base-hw/src/core/include/kernel/double_list.h index 2783a70179..a4129eb751 100644 --- a/repos/base-hw/src/core/include/kernel/double_list.h +++ b/repos/base-hw/src/core/include/kernel/double_list.h @@ -1,5 +1,5 @@ /* - * \brief Double connected list + * \brief List of double connected items * \author Martin Stein * \date 2012-11-30 */ @@ -14,157 +14,172 @@ #ifndef _KERNEL__DOUBLE_LIST_H_ #define _KERNEL__DOUBLE_LIST_H_ -/* core includes */ -#include - namespace Kernel { /** * Ability to be an item in a double connected list - * - * \param T object type that inherits from Double_list_item */ - template class Double_list_item; /** - * Double connected list - * - * \param T object type that inherits from Double_list_item + * List of double connected items */ - template class Double_list; + + /** + * Double list over objects of type 'T' that inherits from double-list item + */ + template class Double_list_typed; } -template class Kernel::Double_list_item { - friend class Double_list; + friend class Double_list; private: - Double_list_item * _next; - Double_list_item * _prev; - Double_list * _list; - - /** - * Return the object behind this item - */ - T * _object() { return static_cast(this); } + Double_list_item * _next; + Double_list_item * _prev; + Double_list * _list; protected: - /** - * Return wether this item is managed by a list currently - */ + Double_list_item() : _list(0) { } + bool _listed() const { return _list; } - - public: - - /** - * Constructor - */ - Double_list_item() : _next(0), _prev(0), _list(0) { } }; -template class Kernel::Double_list { - public: - - typedef Double_list_item Item; - 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; + } + public: /** - * Constructor + * Construct empty list */ Double_list(): _head(0), _tail(0) { } /** - * Insert item 't' from behind into list + * Move item 'i' from its current list position to the tail */ - void insert_tail(Item * const i) + void to_tail(Item * const i) { - /* assertions */ - assert(!i->_list); - - /* update new item */ - i->_prev = _tail; - i->_next = 0; - i->_list = this; - - /* update rest of the list */ - if (_tail) { _tail->_next = i; } - else { _head = i; } - _tail = i; + if (i == _head) { head_to_tail(); } + else { _to_tail(i); } } /** - * Remove item 't' from list + * 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; + i->_list = this; + } + + /** + * 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; + i->_list = this; + } + + /** + * Remove item 'i' from list */ void remove(Item * const i) { - /* assertions */ - assert(i->_list == this); - - /* update next item or _tail */ - if (i != _tail) { i->_next->_prev = i->_prev; } - else { _tail = i->_prev; } - - /* update previous item or _head */ - if (i != _head) { i->_prev->_next = i->_next; } - else { _head = i->_next; } - - /* update removed item */ + if (i == _tail) { _tail = i->_prev; } + else { i->_next->_prev = i->_prev; } + if (i == _head) { _head = i->_next; } + else { i->_prev->_next = i->_next; } i->_list = 0; } /** - * Remove head from list and insert it at the end + * Move head item of list to tail position */ void head_to_tail() { - /* exit if nothing to do */ if (!_head || _head == _tail) { return; } - - /* remove head */ - Item * const i = _head; + _head->_prev = _tail; + _tail->_next = _head; _head = _head->_next; - i->_next = 0; _head->_prev = 0; - - /* insert tail */ - _tail->_next = i; - i->_prev = _tail; - _tail = i; + _tail = _tail->_next; + _tail->_next = 0; } /** - * Call a function for each object in the list - * - * \param function targeted function of type 'void function(T *)' + * Call function 'f' of type 'void (Item *)' for each item in the list */ - template - void for_each(Function function) - { - Item * i = _head; - while (i) { - function(i->_object()); - i = i->_next; - } - } + template void for_each(F f) { + for (Item * i = _head; i; i = i->_next) { f(i); } } - /*************** - ** Accessors ** - ***************/ + /* + * Accessors + */ - T * head() const { return _head ? _head->_object() : 0; } + Item * head() const { return _head; } + static Item * next(Item * const i) { return i->_next; } +}; + +template class Kernel::Double_list_typed : public Double_list +{ + private: + + typedef Double_list_item Item; + + static T * _typed(Item * const i) { + return i ? static_cast(i) : 0; } + + public: + + /* + * 'Double_list' interface + */ + + template void for_each(F f) { + Double_list::for_each([&] (Item * const i) { f(_typed(i)); }); } + + void to_tail(T * const t) { Double_list::to_tail(t); } + void insert_tail(T * const t) { Double_list::insert_tail(t); } + void insert_head(T * const t) { Double_list::insert_head(t); } + void remove(T * const t) { Double_list::remove(t); } + static T * next(T * const t) { return _typed(Double_list::next(t)); } + T * head() const { return _typed(Double_list::head()); } }; #endif /* _KERNEL__DOUBLE_LIST_H_ */ diff --git a/repos/base-hw/src/core/include/kernel/processor.h b/repos/base-hw/src/core/include/kernel/processor.h index 5dd9728c64..741ff1d7c9 100644 --- a/repos/base-hw/src/core/include/kernel/processor.h +++ b/repos/base-hw/src/core/include/kernel/processor.h @@ -61,9 +61,7 @@ namespace Kernel Processor_pool * processor_pool(); } -class Kernel::Processor_domain_update -: - public Double_list_item +class Kernel::Processor_domain_update : public Double_list_item { friend class Processor_domain_update_list; diff --git a/repos/base-hw/src/core/include/kernel/scheduler.h b/repos/base-hw/src/core/include/kernel/scheduler.h index 75cfdc2a45..7f5fdb1dc4 100644 --- a/repos/base-hw/src/core/include/kernel/scheduler.h +++ b/repos/base-hw/src/core/include/kernel/scheduler.h @@ -76,7 +76,7 @@ class Kernel::Priority * Ability to be item in a scheduler through inheritance */ template -class Kernel::Scheduler_item : public Double_list::Item +class Kernel::Scheduler_item : public Double_list_item { private: @@ -87,7 +87,7 @@ class Kernel::Scheduler_item : public Double_list::Item /** * Return wether this item is managed by a scheduler currently */ - bool _scheduled() const { return Double_list::Item::_listed(); } + bool _scheduled() const { return Double_list_item::_listed(); } public: @@ -111,10 +111,10 @@ class Kernel::Scheduler { private: - T * const _idle; - T * _occupant; - Double_list _items[Priority::MAX + 1]; - bool _yield; + T * const _idle; + T * _occupant; + Double_list_typed _items[Priority::MAX + 1]; + bool _yield; bool _does_update(T * const occupant) { diff --git a/repos/base-hw/src/core/kernel/processor.cc b/repos/base-hw/src/core/kernel/processor.cc index be83bc57f9..9c6de09e43 100644 --- a/repos/base-hw/src/core/kernel/processor.cc +++ b/repos/base-hw/src/core/kernel/processor.cc @@ -38,7 +38,7 @@ namespace Kernel class Kernel::Processor_domain_update_list : - public Double_list + public Double_list_typed { public: diff --git a/repos/base-hw/src/test/double_list/kernel/test.cc b/repos/base-hw/src/test/double_list/kernel/test.cc new file mode 100644 index 0000000000..fefe2c89ce --- /dev/null +++ b/repos/base-hw/src/test/double_list/kernel/test.cc @@ -0,0 +1,215 @@ +/* + * \brief Test double-list implementation of the kernel + * \author Martin Stein + * \date 2014-09-30 + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* base includes */ +#include +#include + +/* core includes */ +#include + + +/* + * Utilities + */ + +using Genode::size_t; +using Kernel::Double_list_typed; +using Kernel::Double_list_item; + +namespace Kernel { void test(); } + +void * operator new(size_t s, void * p) { return p; } + +struct Item_load { char volatile x, y, z; }; + +struct Item : Item_load, Double_list_item +{ + unsigned _id; + + Item(unsigned const id) : _id(id) { x = 1; y = 2; z = 3; } + + void iteration() { Genode::printf(" %u", _id); } +}; + +struct Data +{ + static constexpr unsigned nr_of_items = 9; + + Double_list_typed list; + char items[nr_of_items][sizeof(Item)]; + + Data() + { + for (unsigned i = 0; i < nr_of_items; i++) { + new (&items[i]) Item(i + 1); } + } +}; + +Data * data() +{ + static Data d; + return &d; +} + +void done() +{ + Genode::printf("[test] done\n"); + while (1) ; +} + +void check(unsigned i1, unsigned l) +{ + Item * const i2 = data()->list.head(); + if (i1 && i2) { + if(i1 == i2->_id) { return; } + Genode::printf("[test] head %u in line %u\n", i2->_id, l); + done(); + } else if (i1 && !i2) { + Genode::printf("[test] empty in line %u\n", l); + done(); + } else if (!i1 && i2){ + Genode::printf("[test] non-empty %u in line %u\n", i2->_id, l); + done(); + } +} + +void print_each() +{ + Genode::printf("[test] print each"); + data()->list.for_each([] (Item * const i) { i->iteration(); }); + Genode::printf("\n"); +} + +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 Kernel::test() +{ + /* + * 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(); +} diff --git a/repos/base-hw/src/test/double_list/target.mk b/repos/base-hw/src/test/double_list/target.mk new file mode 100644 index 0000000000..ae3570d649 --- /dev/null +++ b/repos/base-hw/src/test/double_list/target.mk @@ -0,0 +1,14 @@ +# +# \brief Build config for a core that tests its double-list implementation +# \author Martin Stein +# \date 2011-12-16 +# + +# set target name that this configuration applies to +TARGET = test-double_list + +# library that provides the whole configuration +LIBS += core + +# add C++ sources +SRC_CC += kernel/test.cc