// -*- Mode: C++ -*- // vim:ft=cpp /** * \file * Capability allocator */ /* * (c) 2008-2009 Adam Lackorzynski , * Alexander Warg * economic rights: Technische Universität Dresden (Germany) * * This file is part of TUD:OS and distributed under the terms of the * GNU General Public License 2. * Please see the COPYING-GPL-2 file for details. * * As a special exception, you may use this file as part of a free software * library without restriction. Specifically, if other files instantiate * templates or use macros or inline functions from this file, or you compile * this file and link it with other files to produce an executable, this * file does not by itself cause the resulting executable to be covered by * the GNU General Public License. This exception does not however * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. */ #pragma once #include #include #include #include namespace L4Re { namespace Util { /** * \defgroup l4re_cap_api L4Re Capability API * \ingroup api_l4re_util */ /*@{*/ /** * Capability allocator. * * This is the instance of the capability allocator that is used * by usual applications. The actual implementation of the allocator * depends on the configuration of the system. * * Per default we use Counting_cap_alloc, a reference-counting * capability allocator, that * keeps a reference counter for each managed capability selector. * * \note This capability allocator is not thread-safe. */ extern _Cap_alloc &cap_alloc; /** * Helper for Unique_cap and Unique_del_cap. */ template< unsigned long Unmap_flags = L4_FP_ALL_SPACES > class Smart_cap_auto { public: /** * Free operation for L4::Smart_cap. */ static void free(L4::Cap_base &c) { if (c.is_valid()) { cap_alloc.free(L4::Cap(c.cap()), This_task, Unmap_flags); c.invalidate(); } } /** * Invalidate operation for L4::Smart_cap. */ static void invalidate(L4::Cap_base &c) { if (c.is_valid()) c.invalidate(); } /** * Copy operation for L4::Smart_cap. */ static L4::Cap_base copy(L4::Cap_base const &src) { L4::Cap_base r = src; invalidate(const_cast(src)); return r; } }; /** * Helper for Ref_cap and Ref_del_cap. */ template< unsigned long Unmap_flags = L4_FP_ALL_SPACES > class Smart_count_cap { public: /** * Free operation for L4::Smart_cap * (decrement ref count and delete if 0). */ static void free(L4::Cap_base &c) noexcept { if (c.is_valid()) { if (cap_alloc.release(L4::Cap(c.cap()), This_task, Unmap_flags)) c.invalidate(); } } /** * Invalidate operation for L4::Smart_cap. */ static void invalidate(L4::Cap_base &c) noexcept { if (c.is_valid()) c.invalidate(); } /** * Copy operation for L4::Smart_cap (increment ref count). */ static L4::Cap_base copy(L4::Cap_base const &src) { cap_alloc.take(L4::Cap(src.cap())); return src; } }; /** * Automatic capability that implements automatic free and * unmap of the capability selector. * * \tparam T Type of the object that is referred by the capability. * * This kind of automatic capability implements a counted reference to a * capability selector. The capability shall be unmapped and freed * when the reference count in the allocator goes to zero. * * Usage: * ~~~ * L4Re::Util::Ref_cap::Cap global_ds_cap; * * { * L4Re::Util::Ref_cap::Cap * ds_cap(L4Re::Util::cap_alloc.alloc()); * // reference count for the allocated cap selector is now 1 * * // use the dataspace cap * L4Re::chksys(mem_alloc->alloc(4096, ds_cap.get())); * * global_ds_cap = ds_cap; * // reference count is now 2 * ... * } * // reference count dropped to 1 (ds_cap is no longer existing). * ~~~ */ template< typename T > struct Ref_cap { typedef L4::Smart_cap > Cap; }; /** * Automatic capability that implements automatic free and * unmap+delete of the capability selector. * * \tparam T Type of the object that is referred by the capability. * * This kind of automatic capability implements a counted reference to a * capability selector. The capability shall be unmapped and freed * when the reference count in the allocator goes to zero. * The main difference to Ref_cap is that the unmap is done with the * deletion flag enabled and this leads to the deletion of the object * if the current task holds appropriate deletion rights. * * Usage: * ~~~ * L4Re::Util::Ref_del_cap::Cap global_ds_cap; * * { * L4Re::Util::Ref_del_cap::Cap * ds_cap(L4Re::Util::cap_alloc.alloc()); * // reference count for the allocated cap selector is now 1 * * // use the dataspace cap * L4Re::chksys(mem_alloc->alloc(4096, ds_cap.get())); * * global_ds_cap = ds_cap; * // reference count is now 2 * ... * } * // reference count dropped to 1 (ds_cap is no longer existing). * ... * global_ds_cap = L4_INVALID_CAP; * // reference count dropped to 0 (data space shall be deleted). * ~~~ */ template< typename T > struct Ref_del_cap { typedef L4::Smart_cap > Cap; }; /** * Allocate a capability slot and wrap it in a Ref_cap. * * \tparam T Type of capability the slot is used for. */ template< typename T > typename Ref_cap::Cap make_ref_cap() { return typename Ref_cap::Cap(cap_alloc.alloc()); } /** * Allocate a capability slot and wrap it in a Ref_del_cap. * * \tparam T Type of capability the slot is used for. */ template< typename T > typename Ref_del_cap::Cap make_ref_del_cap() { return typename Ref_del_cap::Cap(cap_alloc.alloc()); } /*@}*/ }}