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