L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
slab_alloc
1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
4 * Alexander Warg <warg@os.inf.tu-dresden.de>
5 * economic rights: Technische Universität Dresden (Germany)
6 *
7 * License: see LICENSE.spdx (in this directory or the directories above)
8 */
9
10#pragma once
11
12#include <l4/cxx/std_alloc>
13#include <l4/cxx/hlist>
14#include <l4/sys/consts.h>
15
16namespace cxx {
17
29template< int Obj_size, int Slab_size = L4_PAGESIZE,
30 int Max_free = 2, template<typename A> class Alloc = New_allocator >
32{
33private:
34 struct Free_o
35 {
36 Free_o *next;
37 };
38
39protected:
40 struct Slab_i;
41
42private:
43 struct Slab_head : public H_list_item
44 {
46 unsigned num_free;
48 Free_o *free;
51
52 inline Slab_head() noexcept : num_free(0), free(0), cache(0)
53 {}
54 };
55
56 // In an empty or partially filled slab, each free object stores a pointer to
57 // the next free object. Thus, the size of an object needs to be at least the
58 // size of a pointer.
59 static_assert(Obj_size >= sizeof(void *),
60 "Object size must be at least the size of a pointer.");
61 static_assert(Obj_size <= Slab_size - sizeof(Slab_head),
62 "Object_size exceeds slab capability.");
63
64public:
65 enum
66 {
68 object_size = Obj_size,
70 slab_size = Slab_size,
72 objects_per_slab = (Slab_size - sizeof(Slab_head)) / object_size,
74 max_free_slabs = Max_free,
75 };
76
77protected:
78 struct Slab_store
79 {
80 char _o[slab_size - sizeof(Slab_head)];
81 Free_o *object(unsigned obj) noexcept
82 { return reinterpret_cast<Free_o*>(_o + object_size * obj); }
83 };
84
86 struct Slab_i : public Slab_store, public Slab_head
87 {};
88
89public:
91 typedef Alloc<Slab_i> Slab_alloc;
92
93 typedef void Obj_type;
94
95private:
97 Slab_alloc _alloc;
99 unsigned _num_free;
101 unsigned _num_slabs;
103 H_list<Slab_i> _full_slabs;
105 H_list<Slab_i> _partial_slabs;
107 H_list<Slab_i> _empty_slabs;
108
110 void add_slab(Slab_i *s) noexcept
111 {
112 s->num_free = objects_per_slab;
113 s->cache = this;
114
115 //L4::cerr << "Slab: " << this << "->add_slab(" << s << ", size="
116 // << slab_size << "):" << " f=" << s->object(0) << '\n';
117
118 // initialize free list
119 Free_o *f = s->free = s->object(0);
120 for (unsigned i = 1; i < objects_per_slab; ++i)
121 {
122 f->next = s->object(i);
123 f = f->next;
124 }
125 f->next = 0;
126
127 // insert slab into cache's list
128 _empty_slabs.push_front(s);
129 ++_num_slabs;
130 ++_num_free;
131 }
132
134 bool grow() noexcept
135 {
136 Slab_i *s = _alloc.alloc();
137 if (!s)
138 return false;
139
140 new (s, cxx::Nothrow()) Slab_i();
141
142 add_slab(s);
143 return true;
144 }
145
155 void shrink() noexcept
156 {
157 if (!_alloc.can_free)
158 return;
159
160 while (!_empty_slabs.empty() && _num_free > max_free_slabs)
161 {
162 Slab_i *s = _empty_slabs.front();
163 _empty_slabs.remove(s);
164 --_num_free;
165 --_num_slabs;
166 _alloc.free(s);
167 }
168 }
169
170public:
171 Base_slab(Slab_alloc const &alloc = Slab_alloc()) noexcept
172 : _alloc(alloc), _num_free(0), _num_slabs(0), _full_slabs(),
173 _partial_slabs(), _empty_slabs()
174 {}
175
176 ~Base_slab() noexcept
177 {
178 while (!_empty_slabs.empty())
179 {
180 Slab_i *o = _empty_slabs.front();
181 _empty_slabs.remove(o);
182 _alloc.free(o);
183 }
184 while (!_partial_slabs.empty())
185 {
186 Slab_i *o = _partial_slabs.front();
187 _partial_slabs.remove(o);
188 _alloc.free(o);
189 }
190 while (!_full_slabs.empty())
191 {
192 Slab_i *o = _full_slabs.front();
193 _full_slabs.remove(o);
194 _alloc.free(o);
195 }
196 }
197
207 void *alloc() noexcept
208 {
209 H_list<Slab_i> *free = &_partial_slabs;
210 if (free->empty())
211 free = &_empty_slabs;
212
213 if (free->empty() && !grow())
214 return 0;
215
216 Slab_i *s = free->front();
217 Free_o *o = s->free;
218 s->free = o->next;
219
220 if (free == &_empty_slabs)
221 {
222 _empty_slabs.remove(s);
223 --_num_free;
224 }
225
226 --(s->num_free);
227
228 if (!s->free)
229 {
230 _partial_slabs.remove(s);
231 _full_slabs.push_front(s);
232 }
233 else if (free == &_empty_slabs)
234 _partial_slabs.push_front(s);
235
236 //L4::cerr << this << "->alloc(): " << o << ", of " << s << '\n';
237
238 return o;
239 }
240
246 void free(void *_o) noexcept
247 {
248 if (!_o)
249 return;
250
251 unsigned long addr = reinterpret_cast<unsigned long>(_o);
252
253 // find out the slab the object is in
254 addr = (addr / slab_size) * slab_size;
255 Slab_i *s = reinterpret_cast<Slab_i*>(addr);
256
257 if (s->cache != this)
258 return;
259
260 Free_o *o = reinterpret_cast<Free_o*>(_o);
261
262 o->next = s->free;
263 s->free = o;
264
265 bool was_full = false;
266
267 if (!s->num_free)
268 {
269 _full_slabs.remove(s);
270 was_full = true;
271 }
272
273 ++(s->num_free);
274
275 if (s->num_free == objects_per_slab)
276 {
277 if (!was_full)
278 _partial_slabs.remove(s);
279
280 _empty_slabs.push_front(s);
281 ++_num_free;
282 if (_num_free > max_free_slabs)
283 shrink();
284
285 was_full = false;
286 }
287 else if (was_full)
288 _partial_slabs.push_front(s);
289
290 //L4::cerr << this << "->free(" << _o << "): of " << s << '\n';
291 }
292
299 unsigned total_objects() const noexcept
300 { return _num_slabs * objects_per_slab; }
301
308 unsigned free_objects() const noexcept
309 {
310 unsigned count = 0;
311
312 /* count partial slabs first */
313 for (typename H_list<Slab_i>::Const_iterator s = _partial_slabs.begin();
314 s != _partial_slabs.end(); ++s)
315 count += s->num_free;
316
317 /* add empty slabs */
318 count += _num_free * objects_per_slab;
319
320 return count;
321 }
322};
323
333template<typename Type, int Slab_size = L4_PAGESIZE,
334 int Max_free = 2, template<typename A> class Alloc = New_allocator >
335class Slab : public Base_slab<sizeof(Type), Slab_size, Max_free, Alloc>
336{
337private:
338 typedef Base_slab<sizeof(Type), Slab_size, Max_free, Alloc> Base_type;
339public:
340
341 typedef Type Obj_type;
342
343 Slab(typename Base_type::Slab_alloc const &alloc
344 = typename Base_type::Slab_alloc()) noexcept
346
347
355 Type *alloc() noexcept
356 {
357 return reinterpret_cast<Type *>(Base_type::alloc());
358 }
359
366 void free(Type *o) noexcept
367 { Base_slab<sizeof(Type), Slab_size, Max_free, Alloc>::free(o); }
368};
369
370
386template< int Obj_size, int Slab_size = L4_PAGESIZE,
387 int Max_free = 2, template<typename A> class Alloc = New_allocator >
389{
390private:
392 static _A _a;
393public:
394 typedef void Obj_type;
395 enum
396 {
398 object_size = Obj_size,
400 slab_size = Slab_size,
404 max_free_slabs = Max_free,
405 };
406
412 void *alloc() noexcept { return _a.alloc(); }
413
420 void free(void *p) noexcept { _a.free(p); }
421
430 unsigned total_objects() const noexcept { return _a.total_objects(); }
431
440 unsigned free_objects() const noexcept { return _a.free_objects(); }
441};
442
443
444template< int _O, int _S, int _M, template<typename A> class Alloc >
445typename Base_slab_static<_O,_S,_M,Alloc>::_A
446 Base_slab_static<_O,_S,_M,Alloc>::_a;
447
463template<typename Type, int Slab_size = L4_PAGESIZE,
464 int Max_free = 2, template<typename A> class Alloc = New_allocator >
466: public Base_slab_static<sizeof(Type), Slab_size, Max_free, Alloc>
467{
468public:
469
470 typedef Type Obj_type;
478 Type *alloc() noexcept
479 {
480 return reinterpret_cast<Type *>(
481 Base_slab_static<sizeof(Type), Slab_size, Max_free, Alloc>::alloc());
482 }
483};
484
485}
Merged slab allocator (allocators for objects of the same size are merged together).
Definition slab_alloc:389
unsigned total_objects() const noexcept
Get the total number of objects managed by the slab allocator.
Definition slab_alloc:430
void * alloc() noexcept
Allocate an object.
Definition slab_alloc:412
void free(void *p) noexcept
Free the given object (p).
Definition slab_alloc:420
@ max_free_slabs
Maximum number of free slabs.
Definition slab_alloc:404
@ slab_size
Size of a slab.
Definition slab_alloc:400
@ objects_per_slab
Number of objects per slab.
Definition slab_alloc:402
@ object_size
Size of an object.
Definition slab_alloc:398
unsigned free_objects() const noexcept
Get the number of free objects in the slab allocator.
Definition slab_alloc:440
Basic slab allocator.
Definition slab_alloc:32
unsigned free_objects() const noexcept
Get the number of objects which can be allocated before a new empty slab needs to be added to the sla...
Definition slab_alloc:308
Alloc< Slab_i > Slab_alloc
Type of the backend allocator.
Definition slab_alloc:91
void * alloc() noexcept
Allocate a new object.
Definition slab_alloc:207
@ max_free_slabs
Maximum number of free slabs.
Definition slab_alloc:74
@ slab_size
Size of a slab.
Definition slab_alloc:70
@ object_size
Size of an object.
Definition slab_alloc:68
@ objects_per_slab
Objects per slab.
Definition slab_alloc:72
unsigned total_objects() const noexcept
Get the total number of objects managed by the slab allocator.
Definition slab_alloc:299
void free(void *_o) noexcept
Free the given object (_o).
Definition slab_alloc:246
Const_iterator end() const
Return a const iterator to the end of the list.
bool empty() const
Check if the list is empty.
Iterator begin()
Return an iterator to the beginning of the list.
Value_type front() const
Return the first element in the list.
Basic element type for a double-linked H_list.
Definition hlist:23
General double-linked list of unspecified cxx::H_list_item elements.
Definition hlist:70
static void remove(T *e)
Remove the given element from its list.
Definition hlist:220
void push_front(T *e)
Add element to the front of the list.
Definition hlist:109
Helper type to distinguish the operator new version that does not throw exceptions.
Definition std_alloc:19
Merged slab allocator (allocators for objects of the same size are merged together).
Definition slab_alloc:467
Type * alloc() noexcept
Allocate an object of type Type.
Definition slab_alloc:478
Slab allocator for object of type Type.
Definition slab_alloc:336
Type * alloc() noexcept
Allocate an object of type Type.
Definition slab_alloc:355
void free(Type *o) noexcept
Free the object addressed by o.
Definition slab_alloc:366
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:395
Our C++ library.
Definition arith:11
Type of a slab.
Definition slab_alloc:87