From 8768a6dae28fd7c6cf783d3d1d0ef05abc518fce Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Sat, 7 Jun 2014 20:36:02 +0200 Subject: [PATCH] os: New utility for managing object handles Some session interfaces use session-local handles for referring to server-side objects, e.g., a file-system session hands out file handles to the client. The new 'Handle_registry' class template can be used to associate numeric handles with objects on the server side and thereby simplifies the implementation of such servers. --- repos/os/include/os/handle_registry.h | 193 ++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 repos/os/include/os/handle_registry.h diff --git a/repos/os/include/os/handle_registry.h b/repos/os/include/os/handle_registry.h new file mode 100644 index 0000000000..3f7c59caea --- /dev/null +++ b/repos/os/include/os/handle_registry.h @@ -0,0 +1,193 @@ +/* + * \brief Utility for managing object handles + * \author Norman Feske + * \date 2014-06-07 + */ + +/* + * 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. + */ + +#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()' function 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); } +}; + +#endif /* _INCLUDE__OS__HANDLE_REGISTRY_H_ */