/* * \brief Thread-safe object registry * \author Norman Feske * \date 2016-11-06 */ /* * Copyright (C) 2016-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__BASE__REGISTRY_H_ #define _INCLUDE__BASE__REGISTRY_H_ #include #include #include namespace Genode { class Registry_base; template struct Registry; template class Registered; template class Registered_no_delete; } class Genode::Registry_base { private: struct Notify { enum Keep { KEEP, DISCARD } keep; void * const thread; Notify(Keep k, void *t) : keep(k), thread(t) { } }; protected: class Element : public List::Element { private: friend class Registry_base; Registry_base &_registry; /** * Protect '_reinsert_ptr' */ Lock _lock { }; /* * Assigned by 'Registry::_for_each' */ Notify *_notify_ptr = nullptr; /* * Noncopyable */ Element(Element const &); Element &operator = (Element const &); protected: void * const _obj; public: Element(Registry_base &, void *); ~Element(); }; protected: Lock mutable _lock { }; /* protect '_elements' */ List _elements { }; private: /** * Element currently processed by '_for_each' */ Element const *_curr = nullptr; void _insert(Element &); void _remove(Element &); Element *_processed(Notify &, List &, Element &, Element *); protected: struct Untyped_functor : Interface { virtual void call(void *obj_ptr) = 0; }; void _for_each(Untyped_functor &); }; template struct Genode::Registry : private Registry_base { struct Element : Registry_base::Element { friend class Registry; /* allow 'for_each' to access '_obj' */ Element(Registry ®istry, T &obj) : Registry_base::Element(registry, &obj) { } }; template void for_each(FUNC const &fn) { struct Typed_functor : Registry_base::Untyped_functor { FUNC const &_fn; Typed_functor(FUNC const &fn) : _fn(fn) { } void call(void *obj_ptr) override { T &obj = *reinterpret_cast(obj_ptr); _fn(obj); } } untyped_functor(fn); Registry_base::_for_each(untyped_functor); } template void for_each(FUNC const &fn) const { Lock::Guard lock_guard(_lock); Registry_base::Element const *e = _elements.first(), *next = nullptr; for ( ; e; e = next) { next = e->next(); Element const &typed_element = static_cast(*e); T const &obj = *reinterpret_cast(typed_element._obj); fn(obj); } } }; /** * Convenience helper to equip a type 'T' with a 'Registry::Element' * * Using this helper, an arbitrary type can be turned into a registry element * type. E.g., in order to keep 'Child_service' objects in a registry, a new * registry-compatible type can be created via 'Registered'. * Objects of this type can be kept in a 'Registry >'. * The constructor of such "registered" objects expect the registry as the * first argument. The other arguments are forwarded to the constructor of the * enclosed type. */ template class Genode::Registered : public T { private: typename Registry >::Element _element; public: /** * Compile-time check * * \noapi */ static_assert(__has_virtual_destructor(T), "registered object must have virtual destructor"); template Registered(Registry > ®istry, ARGS &&... args) : T(args...), _element(registry, *this) { } }; /** * Variant of Registered that does not require a vtable in the base class * * The generic 'Registered' convenience class requires the base class to * provide a vtable resp. a virtual destructor for safe deletion of a base * class pointer. By using 'Registered_no_delete', this requirement can be * lifted. */ template class Genode::Registered_no_delete : public T { private: typename Registry >::Element _element; public: template Registered_no_delete(Registry > ®istry, ARGS &&... args) : T(args...), _element(registry, *this) { } }; #endif /* _INCLUDE__BASE__REGISTRY_H_ */