/* * \brief Utility for managing object handles * \author Norman Feske * \date 2014-06-07 */ /* * 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. */ #ifndef _INCLUDE__OS__HANDLE_REGISTRY_H_ #define _INCLUDE__OS__HANDLE_REGISTRY_H_ #include #include #include namespace Genode { template class Handle; template class Handle_registry; } /** * Typed handle */ template class Genode::Handle { private: static constexpr unsigned _invalid() { return ~0; } unsigned _value = _invalid(); public: typedef T Type; Handle() { } Handle(unsigned value) : _value(value) { } unsigned value() const { return _value; } bool valid() const { return _value != _invalid(); } bool operator == (Handle const &other) const { return other.value() == _value; } }; /** * Registry of handles, which refer to objects * * \param HANDLE handle type * \param OBJ type of context associated with a handle * * The constructor of the 'HANDLE' type must take an unsigned value as argument * and have a 'value()' method that returns the same value. * * The 'OBJ' type must be inherited from 'Weak_object'. */ template class Genode::Handle_registry { private: /** * Meta data that keeps the association of a handle with an object */ struct Element : public Avl_node, public HANDLE, public Weak_ptr { Element(Weak_ptr weak_ptr, unsigned id) : HANDLE(id), Weak_ptr(weak_ptr) { } /** * Avl_node interface */ bool higher(Element *e) { return e->HANDLE::value() > HANDLE::value(); } /** * Traverse AVL tree to find handle by id */ Element *find_by_handle(HANDLE const &handle) { if (handle.value() == HANDLE::value()) return this; Element * const e = Avl_node::child(handle.value() > HANDLE::value()); return e ? e->find_by_handle(handle) : 0; } }; Tslab _slab; unsigned _cnt = 0; Avl_tree _elements { }; Element &_lookup(HANDLE handle) const { Element *result = nullptr; if (_elements.first()) result = _elements.first()->find_by_handle(handle); if (result) return *result; throw Lookup_failed(); } public: /** * Constructor * * \param alloc allocator used for allocating the meta data for the * handles */ Handle_registry(Allocator &alloc) : _slab(&alloc) { } ~Handle_registry() { while (_elements.first()) free(*_elements.first()); } /** * Exception types */ class Lookup_failed { }; class Out_of_memory { }; /** * Allocate handle for specified object * * \param handle designated handle to assign to the object. By * default, a new handle gets allocated. * * \throw Out_of_memory */ HANDLE &alloc(OBJ &obj, HANDLE handle = HANDLE()) { /* disassociate original object from supplied handle */ try { if (handle.valid()) free(handle); } catch (Lookup_failed) { } try { Element *e = new (_slab) Element(obj.weak_ptr(), handle.valid() ? handle.value() : ++_cnt); _elements.insert(e); return *e; } catch (Allocator::Out_of_memory) { throw Out_of_memory(); } } /** * Release handle * * \throw Lookup_failed */ void free(HANDLE handle) { Element &e = _lookup(handle); _elements.remove(&e); destroy(_slab, &e); } /** * Lookup pointer to OBJ by a given handle * * \throw Lookup_failed */ Weak_ptr &lookup(HANDLE handle) const { return _lookup(handle); } /** * Return true if 'obj' is registered under the specified handle * * \throw Lookup_failed */ bool has_handle(OBJ const &obj, HANDLE handle) const { return obj.weak_ptr_const() == _lookup(handle); } }; #endif /* _INCLUDE__OS__HANDLE_REGISTRY_H_ */