5 * \brief Reference-counting capability allocator
8 * (c) 2008-2010 Alexander Warg <warg@os.inf.tu-dresden.de>
9 * economic rights: Technische Universität Dresden (Germany)
11 * This file is part of TUD:OS and distributed under the terms of the
12 * GNU General Public License 2.
13 * Please see the COPYING-GPL-2 file for details.
15 * As a special exception, you may use this file as part of a free software
16 * library without restriction. Specifically, if other files instantiate
17 * templates or use macros or inline functions from this file, or you compile
18 * this file and link it with other files to produce an executable, this
19 * file does not by itself cause the resulting executable to be covered by
20 * the GNU General Public License. This exception does not however
21 * invalidate any other reasons why the executable file might be covered by
22 * the GNU General Public License.
27 #include <l4/sys/task>
28 #include <l4/sys/assert.h>
29 #include <l4/re/consts>
31 namespace L4Re { namespace Util {
33 template< typename COUNTER = unsigned char >
39 static Type nil() { return 0; }
41 void free() { _cnt = 0; }
42 bool is_free() const { return _cnt == 0; }
43 void inc() { ++_cnt; }
44 Type dec() { return --_cnt; }
45 void alloc() { _cnt = 1; }
49 * \brief Reference-counting cap allocator
51 * \note The operations in this class are not thread-safe.
53 * \ingroup api_l4re_util
55 template <typename COUNTERTYPE = L4Re::Util::Counter<unsigned char> >
56 class Counting_cap_alloc
59 void operator = (Counting_cap_alloc const &) { }
60 typedef COUNTERTYPE Counter;
70 template <unsigned COUNT>
71 struct Counter_storage
73 COUNTERTYPE _buf[COUNT];
74 typedef COUNTERTYPE Buf_type[COUNT];
75 enum { Size = COUNT };
81 * Create a new, empty allocator.
83 * Needs to be initialized with setup() before it can be used.
85 Counting_cap_alloc() throw()
86 : _items(0), _free_hint(0), _bias(0), _capacity(0)
90 * Set up the backing memory for the allocator.
92 * \param m Pointer to backing memory.
93 * \param capacity Number of capabilities that can be stored.
94 * \param bias First capability id to use by this allocator.
96 void setup(void *m, long capacity, long bias) throw()
105 * Allocated a new capability.
107 * \return The newly allocated capability, invalid if the allocator
110 L4::Cap<void> alloc() throw()
112 if (_free_hint >= _capacity)
113 return L4::Cap_base::Invalid;
115 for (long i = _free_hint; i < _capacity; ++i)
117 if (_items[i].is_free())
122 return L4::Cap<void>((i + _bias) << L4_CAP_SHIFT);
126 return L4::Cap<void>::Invalid;
130 template <typename T>
131 L4::Cap<T> alloc() throw()
133 return L4::cap_cast<T>(alloc());
138 * Increase the reference counter for the capability.
140 * \param cap Capability, whose reference counter should be increased.
142 * If the capability was still free, it will be automatically allocated.
143 * Silently does nothing if the capability is not
144 * managed by this allocator.
146 void take(L4::Cap<void> cap) throw()
148 long c = cap.cap() >> L4_CAP_SHIFT;
161 * Free the capability.
163 * \param cap Capability to free.
164 * \param task If set, task to unmap the capability from.
165 * \param unmap_flags Flags for unmap, see l4_unmap_flags_t.
167 * \pre The capability has been allocated. Calling free twice results
168 * in undefined behaviour.
170 * \return True, if the capability was managed by this allocator.
172 bool free(L4::Cap<void> cap, l4_cap_idx_t task = L4_INVALID_CAP,
173 unsigned unmap_flags = L4_FP_ALL_SPACES) throw()
175 long c = cap.cap() >> L4_CAP_SHIFT;
184 l4_assert(!_items[c].is_free());
186 if (task != L4_INVALID_CAP)
187 l4_task_unmap(task, cap.fpage(), unmap_flags);
198 * Decrease the reference counter for a capability.
200 * \param cap Capability to release.
201 * \param task If set, task to unmap the capability from.
202 * \param unmap_flags Flags for unmap, see l4_unmap_flags_t.
204 * \pre The capability has been allocated. Calling release on a free
205 * capability results in undefined behaviour.
207 * \return True, if the capability was freed as a result of
208 * this operation. If false is returned the capability
209 * is either still in use or was already free or invalid.
211 bool release(L4::Cap<void> cap, l4_cap_idx_t task = L4_INVALID_CAP,
212 unsigned unmap_flags = L4_FP_ALL_SPACES) throw()
214 long c = cap.cap() >> L4_CAP_SHIFT;
223 l4_assert(!_items[c].is_free());
225 if (_items[c].dec() == Counter::nil())
227 if (task != L4_INVALID_CAP)
228 l4_task_unmap(task, cap.fpage(), unmap_flags);
240 * Return highest capability id managed by this allocator.
244 return _capacity + _bias - 1;