L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
counting_cap_alloc
Go to the documentation of this file.
1// vim:set ft=cpp: -*- Mode: C++ -*-
6/*
7 * (c) 2008-2010 Alexander Warg <warg@os.inf.tu-dresden.de>
8 * economic rights: Technische Universität Dresden (Germany)
9 *
10 * License: see LICENSE.spdx (in this directory or the directories above)
11 */
12
13#pragma once
14
15#include <l4/sys/task>
16#include <l4/sys/assert.h>
17#include <l4/re/consts>
18
19namespace L4Re { namespace Util {
20
26template< typename COUNTER = unsigned char >
27struct Counter
28{
29 typedef COUNTER Type;
30 Type _cnt;
31
32 static Type nil() { return 0; }
33 static Type unused() { return 0; }
34
35 void free() { _cnt = 0; }
36 bool is_free() const { return _cnt == 0; }
37 bool is_saturated() const { return static_cast<Type>(_cnt + 1) == 0; }
38
50 bool inc()
51 {
52 if (is_saturated())
53 return true; // no change and no warning
54 ++_cnt;
55 if (is_saturated())
56 return false; // warn caller that counter is now saturated
57 else
58 return true; // success
59 }
60
67 Type dec()
68 {
69 if (is_saturated())
70 return _cnt; // no change
71 else
72 return --_cnt; // success
73 }
74
75 bool try_alloc()
76 {
77 if (_cnt == 0)
78 {
79 _cnt = 1;
80 return true;
81 }
82 return false;
83 }
84};
85
97template< typename COUNTER = unsigned char >
99{
100 typedef COUNTER Type;
101 Type _cnt;
102
103 static Type nil() { return 0; }
104 static Type unused() { return 1; }
105
106 bool is_free() const { return __atomic_load_n(&_cnt, __ATOMIC_RELAXED) == 0; }
107 static bool is_saturated(Type cnt) { return static_cast<Type>(cnt + 1) == 0; }
108
109 bool try_alloc()
110 {
111 Type expected = nil();
112 // Use "acquire" memory ordering. Any operations tied to the capability slot
113 // must only be observable after the slot has been occupied.
114 return __atomic_compare_exchange_n(&_cnt, &expected, 2, false,
115 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
116 }
117
121 bool inc()
122 {
123 Type old_cnt = __atomic_load_n(&_cnt, __ATOMIC_RELAXED);
124 Type new_cnt;
125 do
126 {
127 if (is_saturated(old_cnt))
128 return true; // no change and no warning
129 new_cnt = old_cnt + 1;
130 }
131 while (!__atomic_compare_exchange_n(&_cnt, &old_cnt, new_cnt, false,
132 __ATOMIC_RELAXED, __ATOMIC_RELAXED));
133 if (is_saturated(new_cnt))
134 return false; // warn caller that counter is now saturated
135 else
136 return true; // success
137 }
138
142 Type dec()
143 {
144 Type old_cnt = __atomic_load_n(&_cnt, __ATOMIC_RELAXED);
145 Type new_cnt;
146 do
147 {
148 if (is_saturated(old_cnt))
149 return old_cnt; // no change
150 new_cnt = old_cnt - 1;
151 }
152 while (!__atomic_compare_exchange_n(&_cnt, &old_cnt, new_cnt, false,
153 __ATOMIC_RELAXED, __ATOMIC_RELAXED));
154 return new_cnt; // success
155 }
156
157 void free()
158 {
159 // Use "release" memory ordering to make sure that any operations tied to
160 // the capability slot are observable by other threads before the slot can
161 // be reused.
162 __atomic_store_n(&_cnt, 0, __ATOMIC_RELEASE);
163 }
164};
165
190template <typename COUNTERTYPE, typename Dbg>
192{
193private:
194 void operator = (Counting_cap_alloc const &) { }
195 typedef COUNTERTYPE Counter;
196
197 COUNTERTYPE *_items;
198 long _free_hint;
199 long _bias;
200 long _capacity;
201 Dbg *_dbg;
202
203public:
204
205 template <unsigned COUNT>
206 struct Storage
207 {
208 COUNTERTYPE _buf[COUNT];
209 typedef COUNTERTYPE Buf_type[COUNT];
210 enum { Size = COUNT };
211 };
212
213 Counting_cap_alloc(long capacity, void *m, long bias, Dbg *dbg) noexcept
214 : _items((Counter*)m), _free_hint(0), _bias(bias), _capacity(capacity),
215 _dbg(dbg)
216 {}
217
218protected:
225 : _items(0), _free_hint(0), _bias(0), _capacity(0)
226 {}
227
242 void setup(void *m, long capacity, long bias, Dbg *dbg) noexcept
243 {
244 _items = static_cast<Counter*>(m);
245 _capacity = capacity;
246 _bias = bias;
247 _dbg = dbg;
248 }
249
250public:
258 {
259 long free_hint = __atomic_load_n(&_free_hint, __ATOMIC_RELAXED);
260
261 for (long i = free_hint; i < _capacity; ++i)
262 if (_items[i].try_alloc())
263 {
264 _free_hint = i + 1;
265 return L4::Cap<void>((i + _bias) << L4_CAP_SHIFT);
266 }
267
268 // _free_hint is not necessarily correct in case of multi-threading! Make
269 // sure we don't miss any potentially free slots.
270 for (long i = 0; i < free_hint && i < _capacity; ++i)
271 if (_items[i].try_alloc())
272 {
273 _free_hint = i + 1;
274 return L4::Cap<void>((i + _bias) << L4_CAP_SHIFT);
275 }
276
278 }
279
281 template <typename T>
282 L4::Cap<T> alloc() noexcept
283 {
284 return L4::cap_cast<T>(alloc());
285 }
286
287
296 void take(L4::Cap<void> cap) noexcept
297 {
298 long c;
299 if (!range_check_and_get_idx(cap, &c))
300 return;
301
302 if (!L4_UNLIKELY(_items[c].inc()))
303 _dbg->printf("Warning: Reference counter of cap 0x%lx now saturated!\n",
304 cap.cap() >> L4_CAP_SHIFT);
305 }
306
307
322 unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept
323 {
324 long c;
325 if (!range_check_and_get_idx(cap, &c))
326 return false;
327
328 l4_assert(!_items[c].is_free());
329
330 if (l4_is_valid_cap(task))
331 l4_task_unmap(task, cap.fpage(), unmap_flags);
332
333 if (c < _free_hint)
334 _free_hint = c;
335
336 _items[c].free();
337
338 return true;
339 }
340
360 unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept
361 {
362 long c;
363 if (!range_check_and_get_idx(cap, &c))
364 return false;
365
366 l4_assert(!_items[c].is_free());
367
368 if (_items[c].dec() == Counter::unused())
369 {
370 if (task != L4_INVALID_CAP)
371 l4_task_unmap(task, cap.fpage(), unmap_flags);
372
373 if (c < _free_hint)
374 _free_hint = c;
375
376 // Let others allocate this slot only after the l4_task_unmap() has
377 // finished.
378 _items[c].free();
379
380 return true;
381 }
382 return false;
383 }
384
388 long last() noexcept
389 {
390 return _capacity + _bias - 1;
391 }
392
393private:
394 bool range_check_and_get_idx(L4::Cap<void> cap, long *c)
395 {
396 *c = cap.cap() >> L4_CAP_SHIFT;
397 if (*c < _bias)
398 return false;
399
400 *c -= _bias;
401
402 return *c < _capacity;
403 }
404};
405
406}}
Internal reference-counting cap allocator.
bool release(L4::Cap< void > cap, l4_cap_idx_t task=L4_INVALID_CAP, unsigned unmap_flags=L4_FP_ALL_SPACES) noexcept
Decrease the reference counter for a capability.
void setup(void *m, long capacity, long bias, Dbg *dbg) noexcept
Set up the backing memory for the allocator and the area of managed capability slots.
long last() noexcept
Return highest capability id managed by this allocator.
bool free(L4::Cap< void > cap, l4_cap_idx_t task=L4_INVALID_CAP, unsigned unmap_flags=L4_FP_ALL_SPACES) noexcept
Free the capability.
void take(L4::Cap< void > cap) noexcept
Increase the reference counter for the capability.
L4::Cap< void > alloc() noexcept
Allocate a new capability slot.
L4::Cap< T > alloc() noexcept
Allocate a new capability slot.
Counting_cap_alloc() noexcept
Create a new, empty allocator.
l4_cap_idx_t cap() const noexcept
Return capability selector.
Definition capability.h:49
C++ interface for capabilities.
Definition capability.h:219
unsigned long l4_cap_idx_t
Capability selector type.
Definition types.h:335
unsigned l4_is_valid_cap(l4_cap_idx_t c) L4_NOTHROW
Test if a capability selector is a valid selector.
Definition types.h:392
@ L4_CAP_SHIFT
Capability index shift.
Definition consts.h:146
@ L4_INVALID_CAP
Invalid capability selector.
Definition consts.h:157
l4_msgtag_t l4_task_unmap(l4_cap_idx_t task, l4_fpage_t fpage, l4_umword_t map_mask) L4_NOTHROW
Revoke rights from the task.
Definition task.h:423
@ L4_FP_ALL_SPACES
Flag to tell the unmap operation to revoke permissions from all child mappings including the mapping ...
Definition consts.h:187
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:275
L4Re C++ Interfaces.
Definition cmd_control:14
Constants.
Thread safe version of counter for Counting_cap_alloc.
Type dec()
Decrement counter if not saturated.
bool inc()
Increment counter if not yet saturated.
Counter for Counting_cap_alloc with variable data width.
Type dec()
Decrement counter if not saturated.
bool inc()
Increment counter if not yet saturated.
Low-level assert implementation.
#define l4_assert(expr)
Low-level assert.
Definition assert.h:32
Common task related definitions.