genode/repos/base-hw/src/core/kernel/object.h

238 lines
4.7 KiB
C++

/*
* \brief Objects that are findable through unique IDs
* \author Martin Stein
* \date 2012-11-30
*/
/*
* Copyright (C) 2012-2013 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.
*/
#ifndef _KERNEL__OBJECT_H_
#define _KERNEL__OBJECT_H_
/* Genode includes */
#include <util/avl_tree.h>
#include <base/printf.h>
/* core includes */
#include <assert.h>
namespace Kernel
{
template <typename T> class Avl_tree : public Genode::Avl_tree<T> { };
template <typename T> class Avl_node : public Genode::Avl_node<T> { };
/**
* Map unique sortable IDs to objects
*
* \param T object type that inherits from Object_pool<T>::Item
*/
template <typename T>
class Object_pool;
/**
* Manage allocation of a static set of IDs
*
* \param SIZE amount of allocatable IDs
*/
template <unsigned SIZE>
class Id_allocator;
/**
* Make all objects of a deriving class findable through unique IDs
*
* \param T object type
* \param MAX_INSTANCES max amount of coincidently living objects
* \param ID_ALLOC accessor function of object-name allocator
* \param POOL accessor function of object pool
*
* FIXME: Most of the bother with template parameters regarding ID
* allocator and object pool is caused by the use of
* unsynchronized singletons. By avoiding the use of
* unsynchronized singletons one can at least remove
* ID_ALLOC_T.
*/
template <typename T, unsigned MAX_INSTANCES, typename ID_ALLOC_T,
ID_ALLOC_T * (*ID_ALLOC)(), Kernel::Object_pool<T> * (* POOL)()>
class Object;
}
template <typename T>
class Kernel::Object_pool
{
public:
/**
* Enable a deriving class T to be inserted into an Object_pool<T>
*/
class Item;
/**
* Insert 'object' into pool
*/
void insert(T * const object) { _tree.insert(object); }
/**
* Remove 'object' from pool
*/
void remove(T * const object) { _tree.remove(object); }
/**
* Return object with ID 'id', or 0 if such an object doesn't exist
*/
T * object(unsigned const id) const
{
Item * const root = _tree.first();
if (!root) { return 0; }
return static_cast<T *>(root->find(id));
}
private:
Avl_tree<Item> _tree;
};
template <typename T>
class Kernel::Object_pool<T>::Item : public Avl_node<Item>
{
protected:
unsigned _id;
public:
/**
* Constructor
*/
Item(unsigned const id) : _id(id) { }
/**
* Find entry with 'object_id' within this AVL subtree
*/
Item * find(unsigned const object_id)
{
if (object_id == id()) { return this; }
Item * const subtree = Avl_node<Item>::child(object_id > id());
if (!subtree) { return 0; }
return subtree->find(object_id);
}
/**
* ID of this object
*/
unsigned id() const { return _id; }
/************************
* 'Avl_node' interface *
************************/
bool higher(Item * i) const { return i->id() > id(); }
};
template <unsigned SIZE>
class Kernel::Id_allocator
{
private:
enum {
MIN = 1,
MAX = MIN + SIZE - 1
};
bool _free[MAX + 1];
unsigned _free_id;
/**
* Return wether 'id' is a valid ID
*/
bool _valid_id(unsigned const id) const
{
return id >= MIN && id <= MAX;
}
public:
/**
* Constructor
*/
Id_allocator() : _free_id(MIN)
{
/* free all IDs */
for (unsigned i = MIN; i <= MAX; i++) { _free[i] = 1; }
}
/**
* Allocate a free ID
*
* \return ID that has been allocated by the call
*/
unsigned alloc()
{
/* FIXME: let userland donate RAM to avoid out of mem */
if (!_valid_id(_free_id)) {
PERR("failed to allocate ID");
while (1) { }
}
/* allocate _free_id */
_free[_free_id] = 0;
unsigned const id = _free_id;
/* update _free_id */
_free_id++;
for (; _free_id <= MAX && !_free[_free_id]; _free_id++) { }
return id;
}
/**
* Free ID 'id'
*/
void free(unsigned const id)
{
assert(_valid_id(id));
_free[id] = 1;
if (id < _free_id) { _free_id = id; }
}
};
template <typename T, unsigned MAX_INSTANCES, typename ID_ALLOC_T,
ID_ALLOC_T * (* ID_ALLOC)(), Kernel::Object_pool<T> * (* POOL)()>
class Kernel::Object : public Object_pool<T>::Item
{
public:
typedef Object_pool<T> Pool;
/**
* Map of unique IDs to objects of T
*/
static Pool * pool() { return POOL(); }
protected:
/**
* Constructor
*/
Object() : Pool::Item(ID_ALLOC()->alloc())
{
POOL()->insert(static_cast<T *>(this));
}
/**
* Destructor
*/
~Object()
{
POOL()->remove(static_cast<T *>(this));
ID_ALLOC()->free(Pool::Item::id());
}
};
#endif /* _KERNEL__OBJECT_H_ */