1// -*- Mode: C++ -*- 2// vim:ft=cpp 3/** 4 * \file 5 * Capability allocator 6 */ 7/* 8 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>, 9 * Alexander Warg <warg@os.inf.tu-dresden.de> 10 * economic rights: Technische Universität Dresden (Germany) 11 * 12 * This file is part of TUD:OS and distributed under the terms of the 13 * GNU General Public License 2. 14 * Please see the COPYING-GPL-2 file for details. 15 * 16 * As a special exception, you may use this file as part of a free software 17 * library without restriction. Specifically, if other files instantiate 18 * templates or use macros or inline functions from this file, or you compile 19 * this file and link it with other files to produce an executable, this 20 * file does not by itself cause the resulting executable to be covered by 21 * the GNU General Public License. This exception does not however 22 * invalidate any other reasons why the executable file might be covered by 23 * the GNU General Public License. 24 */ 25 26#pragma once 27 28#include <l4/re/util/cap_alloc_impl.h> 29#include <l4/sys/smart_capability> 30#include <l4/sys/task> 31#include <l4/re/consts> 32 33namespace L4Re { namespace Util { 34 35/** 36 * \defgroup l4re_cap_api L4Re Capability API 37 * \ingroup api_l4re_util 38 */ 39/*@{*/ 40/** 41 * Capability allocator. 42 * 43 * This is the instance of the capability allocator that is used 44 * by usual applications. The actual implementation of the allocator 45 * depends on the configuration of the system. 46 * 47 * Per default we use Counting_cap_alloc, a reference-counting 48 * capability allocator, that 49 * keeps a reference counter for each managed capability selector. 50 * 51 * \note This capability allocator is not thread-safe. 52 */ 53extern _Cap_alloc &cap_alloc; 54 55/** 56 * Helper for Unique_cap and Unique_del_cap. 57 */ 58template< unsigned long Unmap_flags = L4_FP_ALL_SPACES > 59class Smart_cap_auto 60{ 61public: 62 /** 63 * Free operation for L4::Smart_cap. 64 */ 65 static void free(L4::Cap_base &c) 66 { 67 if (c.is_valid()) 68 { 69 cap_alloc.free(L4::Cap<void>(c.cap()), This_task, Unmap_flags); 70 c.invalidate(); 71 } 72 } 73 74 /** 75 * Invalidate operation for L4::Smart_cap. 76 */ 77 static void invalidate(L4::Cap_base &c) 78 { 79 if (c.is_valid()) 80 c.invalidate(); 81 } 82 83 /** 84 * Copy operation for L4::Smart_cap. 85 */ 86 static L4::Cap_base copy(L4::Cap_base const &src) 87 { 88 L4::Cap_base r = src; 89 invalidate(const_cast<L4::Cap_base &>(src)); 90 return r; 91 } 92}; 93 94 95/** 96 * Helper for Ref_cap and Ref_del_cap. 97 */ 98template< unsigned long Unmap_flags = L4_FP_ALL_SPACES > 99class Smart_count_cap 100{ 101public: 102 /** 103 * Free operation for L4::Smart_cap 104 * (decrement ref count and delete if 0). 105 */ 106 static void free(L4::Cap_base &c) noexcept 107 { 108 if (c.is_valid()) 109 { 110 if (cap_alloc.release(L4::Cap<void>(c.cap()), This_task, Unmap_flags)) 111 c.invalidate(); 112 } 113 } 114 115 /** 116 * Invalidate operation for L4::Smart_cap. 117 */ 118 static void invalidate(L4::Cap_base &c) noexcept 119 { 120 if (c.is_valid()) 121 c.invalidate(); 122 } 123 124 /** 125 * Copy operation for L4::Smart_cap (increment ref count). 126 */ 127 static L4::Cap_base copy(L4::Cap_base const &src) 128 { 129 cap_alloc.take(L4::Cap<void>(src.cap())); 130 return src; 131 } 132}; 133 134 135/** 136 * Automatic capability that implements automatic free and 137 * unmap of the capability selector. 138 * 139 * \tparam T Type of the object that is referred by the capability. 140 * 141 * This kind of automatic capability implements a counted reference to a 142 * capability selector. The capability shall be unmapped and freed 143 * when the reference count in the allocator goes to zero. 144 * 145 * Usage: 146 * ~~~ 147 * L4Re::Util::Ref_cap<L4Re::Dataspace>::Cap global_ds_cap; 148 * 149 * { 150 * L4Re::Util::Ref_cap<L4Re::Dataspace>::Cap 151 * ds_cap(L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>()); 152 * // reference count for the allocated cap selector is now 1 153 * 154 * // use the dataspace cap 155 * L4Re::chksys(mem_alloc->alloc(4096, ds_cap.get())); 156 * 157 * global_ds_cap = ds_cap; 158 * // reference count is now 2 159 * ... 160 * } 161 * // reference count dropped to 1 (ds_cap is no longer existing). 162 * ~~~ 163 */ 164template< typename T > 165struct Ref_cap 166{ 167 typedef L4::Smart_cap<T, Smart_count_cap<L4_FP_ALL_SPACES> > Cap; 168}; 169 170/** 171 * Automatic capability that implements automatic free and 172 * unmap+delete of the capability selector. 173 * 174 * \tparam T Type of the object that is referred by the capability. 175 * 176 * This kind of automatic capability implements a counted reference to a 177 * capability selector. The capability shall be unmapped and freed 178 * when the reference count in the allocator goes to zero. 179 * The main difference to Ref_cap is that the unmap is done with the 180 * deletion flag enabled and this leads to the deletion of the object 181 * if the current task holds appropriate deletion rights. 182 * 183 * Usage: 184 * ~~~ 185 * L4Re::Util::Ref_del_cap<L4Re::Dataspace>::Cap global_ds_cap; 186 * 187 * { 188 * L4Re::Util::Ref_del_cap<L4Re::Dataspace>::Cap 189 * ds_cap(L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>()); 190 * // reference count for the allocated cap selector is now 1 191 * 192 * // use the dataspace cap 193 * L4Re::chksys(mem_alloc->alloc(4096, ds_cap.get())); 194 * 195 * global_ds_cap = ds_cap; 196 * // reference count is now 2 197 * ... 198 * } 199 * // reference count dropped to 1 (ds_cap is no longer existing). 200 * ... 201 * global_ds_cap = L4_INVALID_CAP; 202 * // reference count dropped to 0 (data space shall be deleted). 203 * ~~~ 204 */ 205template< typename T > 206struct Ref_del_cap 207{ 208 typedef L4::Smart_cap<T, Smart_count_cap<L4_FP_DELETE_OBJ> > Cap; 209}; 210 211/** 212 * Allocate a capability slot and wrap it in a Ref_cap. 213 * 214 * \tparam T Type of capability the slot is used for. 215 */ 216template< typename T > 217typename Ref_cap<T>::Cap 218make_ref_cap() { return typename Ref_cap<T>::Cap(cap_alloc.alloc<T>()); } 219 220/** 221 * Allocate a capability slot and wrap it in a Ref_del_cap. 222 * 223 * \tparam T Type of capability the slot is used for. 224 */ 225template< typename T > 226typename Ref_del_cap<T>::Cap 227make_ref_del_cap() 228{ return typename Ref_del_cap<T>::Cap(cap_alloc.alloc<T>()); } 229 230/*@}*/ 231 232}} 233 234