mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
hw: enhance and test double-list data-structure
To serve the needs of the coming CPU scheduler, the double list needs additional methods such as 'to_tail' and 'insert_head'. The commit also adds a run script that enables an automated unit test of the list implementation. ref #1225
This commit is contained in:
parent
0ab5310b8a
commit
a00eb9a66a
31
repos/base-hw/run/double_list.run
Normal file
31
repos/base-hw/run/double_list.run
Normal file
@ -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
|
||||
}
|
@ -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 <assert.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
/**
|
||||
* Ability to be an item in a double connected list
|
||||
*
|
||||
* \param T object type that inherits from Double_list_item<T>
|
||||
*/
|
||||
template <typename T>
|
||||
class Double_list_item;
|
||||
|
||||
/**
|
||||
* Double connected list
|
||||
*
|
||||
* \param T object type that inherits from Double_list_item<T>
|
||||
* List of double connected items
|
||||
*/
|
||||
template <typename T>
|
||||
class Double_list;
|
||||
|
||||
/**
|
||||
* Double list over objects of type 'T' that inherits from double-list item
|
||||
*/
|
||||
template <typename T> class Double_list_typed;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Kernel::Double_list_item
|
||||
{
|
||||
friend class Double_list<T>;
|
||||
friend class Double_list;
|
||||
|
||||
private:
|
||||
|
||||
Double_list_item<T> * _next;
|
||||
Double_list_item<T> * _prev;
|
||||
Double_list<T> * _list;
|
||||
|
||||
/**
|
||||
* Return the object behind this item
|
||||
*/
|
||||
T * _object() { return static_cast<T *>(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 <typename T>
|
||||
class Kernel::Double_list
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Double_list_item<T> 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 <typename Function>
|
||||
void for_each(Function function)
|
||||
{
|
||||
Item * i = _head;
|
||||
while (i) {
|
||||
function(i->_object());
|
||||
i = i->_next;
|
||||
}
|
||||
}
|
||||
template <typename F> 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 <typename T> class Kernel::Double_list_typed : public Double_list
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Double_list_item Item;
|
||||
|
||||
static T * _typed(Item * const i) {
|
||||
return i ? static_cast<T *>(i) : 0; }
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* 'Double_list' interface
|
||||
*/
|
||||
|
||||
template <typename F> 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_ */
|
||||
|
@ -61,9 +61,7 @@ namespace Kernel
|
||||
Processor_pool * processor_pool();
|
||||
}
|
||||
|
||||
class Kernel::Processor_domain_update
|
||||
:
|
||||
public Double_list_item<Processor_domain_update>
|
||||
class Kernel::Processor_domain_update : public Double_list_item
|
||||
{
|
||||
friend class Processor_domain_update_list;
|
||||
|
||||
|
@ -76,7 +76,7 @@ class Kernel::Priority
|
||||
* Ability to be item in a scheduler through inheritance
|
||||
*/
|
||||
template <typename T>
|
||||
class Kernel::Scheduler_item : public Double_list<T>::Item
|
||||
class Kernel::Scheduler_item : public Double_list_item
|
||||
{
|
||||
private:
|
||||
|
||||
@ -87,7 +87,7 @@ class Kernel::Scheduler_item : public Double_list<T>::Item
|
||||
/**
|
||||
* Return wether this item is managed by a scheduler currently
|
||||
*/
|
||||
bool _scheduled() const { return Double_list<T>::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<T> _items[Priority::MAX + 1];
|
||||
bool _yield;
|
||||
T * const _idle;
|
||||
T * _occupant;
|
||||
Double_list_typed<T> _items[Priority::MAX + 1];
|
||||
bool _yield;
|
||||
|
||||
bool _does_update(T * const occupant)
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ namespace Kernel
|
||||
|
||||
class Kernel::Processor_domain_update_list
|
||||
:
|
||||
public Double_list<Processor_domain_update>
|
||||
public Double_list_typed<Processor_domain_update>
|
||||
{
|
||||
public:
|
||||
|
||||
|
215
repos/base-hw/src/test/double_list/kernel/test.cc
Normal file
215
repos/base-hw/src/test/double_list/kernel/test.cc
Normal file
@ -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 <base/stdint.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/double_list.h>
|
||||
|
||||
|
||||
/*
|
||||
* 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<Item> 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<Item *>(&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
|
||||
* '<ops> C(i) <doc>' 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();
|
||||
}
|
14
repos/base-hw/src/test/double_list/target.mk
Normal file
14
repos/base-hw/src/test/double_list/target.mk
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user