mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-07 20:00:23 +00:00
604d6bf567
Avoid arithmetics on enum values, disambiguate '==' operator of handle_registry. Fixes #4875
206 lines
4.1 KiB
C++
206 lines
4.1 KiB
C++
/*
|
|
* \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 <util/avl_tree.h>
|
|
#include <base/weak_ptr.h>
|
|
#include <base/tslab.h>
|
|
|
|
namespace Genode {
|
|
|
|
template <typename T> class Handle;
|
|
template <typename HANDLE, typename OBJ> class Handle_registry;
|
|
}
|
|
|
|
|
|
/**
|
|
* Typed handle
|
|
*/
|
|
template <typename T>
|
|
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 <typename HANDLE, typename OBJ>
|
|
class Genode::Handle_registry
|
|
{
|
|
private:
|
|
|
|
/**
|
|
* Meta data that keeps the association of a handle with an object
|
|
*/
|
|
struct Element : public Avl_node<Element>,
|
|
public HANDLE,
|
|
public Weak_ptr<OBJ>
|
|
{
|
|
Element(Weak_ptr<OBJ> weak_ptr, unsigned id)
|
|
:
|
|
HANDLE(id), Weak_ptr<OBJ>(weak_ptr)
|
|
{ }
|
|
|
|
using Weak_ptr<OBJ>::operator ==;
|
|
|
|
/**
|
|
* 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<Element>::child(handle.value() > HANDLE::value());
|
|
|
|
return e ? e->find_by_handle(handle) : 0;
|
|
}
|
|
};
|
|
|
|
Tslab<Element, 4000> _slab;
|
|
|
|
unsigned _cnt = 0;
|
|
|
|
Avl_tree<Element> _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<OBJ> &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_ */
|