/* * \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 #include /* core includes */ #include namespace Kernel { template class Avl_tree : public Genode::Avl_tree { }; template class Avl_node : public Genode::Avl_node { }; /** * Map unique sortable IDs to objects * * \param T object type that inherits from Object_pool::Item */ template class Object_pool; /** * Manage allocation of a static set of IDs * * \param SIZE amount of allocatable IDs */ template 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 * (* POOL)()> class Object; } template class Kernel::Object_pool { public: /** * Enable a deriving class T to be inserted into an Object_pool */ 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(root->find(id)); } private: Avl_tree _tree; }; template class Kernel::Object_pool::Item : public Avl_node { 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::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 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 * (* POOL)()> class Kernel::Object : public Object_pool::Item { public: typedef Object_pool 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(this)); } /** * Destructor */ ~Object() { POOL()->remove(static_cast(this)); ID_ALLOC()->free(Pool::Item::id()); } }; #endif /* _KERNEL__OBJECT_H_ */