]> git.ipfire.org Git - thirdparty/bird.git/blame - lib/slab.c
Another pile of ipa_from_u32() calls.
[thirdparty/bird.git] / lib / slab.c
CommitLineData
18c8241a 1/*
35496679 2 * BIRD Resource Manager -- A SLAB-like Memory Allocator
18c8241a 3 *
35496679
MM
4 * Heavily inspired by the original SLAB paper by Jeff Bonwick.
5 *
6 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
18c8241a
MM
7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
5cc1e1f8
MM
11/**
12 * DOC: Slabs
13 *
14 * Slabs are collections of memory blocks of a fixed size.
15 * They support very fast allocation and freeing of such blocks, prevent memory
16 * fragmentation and optimize L2 cache usage. Slabs have been invented by Jeff Bonwick
17 * and published in USENIX proceedings as `The Slab Allocator: An Object-Caching Kernel
18 * Memory Allocator'. Our implementation follows this article except that we don't use
19 * constructors and destructors.
20 *
21 * When the |DEBUGGING| switch is turned on, we automatically fill all
58f7d004 22 * newly allocated and freed blocks with a special pattern to make detection
5cc1e1f8
MM
23 * of use of uninitialized or already freed memory easier.
24 *
58f7d004 25 * Example: Nodes of a FIB are allocated from a per-FIB Slab.
5cc1e1f8
MM
26 */
27
18c8241a 28#include <stdlib.h>
18c8241a
MM
29
30#include "nest/bird.h"
31#include "lib/resource.h"
221135d6 32#include "lib/string.h"
18c8241a 33
35496679
MM
34#undef FAKE_SLAB /* Turn on if you want to debug memory allocations */
35
b8e60d35
MM
36#ifdef DEBUGGING
37#define POISON /* Poison all regions after they are freed */
38#endif
39
35496679
MM
40static void slab_free(resource *r);
41static void slab_dump(resource *r);
c9763428 42static resource *slab_lookup(resource *r, unsigned long addr);
35496679
MM
43
44#ifdef FAKE_SLAB
45
18c8241a 46/*
35496679 47 * Fake version used for debugging.
18c8241a
MM
48 */
49
18c8241a
MM
50struct slab {
51 resource r;
52 unsigned size;
53 list objs;
54};
55
d4bc8dc0 56static struct resclass sl_class = {
35496679 57 "FakeSlab",
18c8241a
MM
58 sizeof(struct slab),
59 slab_free,
60 slab_dump
61};
62
35496679
MM
63struct sl_obj {
64 node n;
65 byte data[0];
66};
67
18c8241a
MM
68slab *
69sl_new(pool *p, unsigned size)
70{
71 slab *s = ralloc(p, &sl_class);
72 s->size = size;
73 init_list(&s->objs);
74 return s;
75}
76
77void *
78sl_alloc(slab *s)
79{
80 struct sl_obj *o = xmalloc(sizeof(struct sl_obj) + s->size);
81
82 add_tail(&s->objs, &o->n);
83 return o->data;
84}
85
86void
87sl_free(slab *s, void *oo)
88{
89 struct sl_obj *o = SKIP_BACK(struct sl_obj, data, oo);
90
91 rem_node(&o->n);
92 xfree(o);
93}
94
d4bc8dc0 95static void
18c8241a
MM
96slab_free(resource *r)
97{
98 slab *s = (slab *) r;
99 struct sl_obj *o, *p;
100
101 for(o = HEAD(s->objs); p = (struct sl_obj *) o->n.next; o = p)
102 xfree(o);
103}
104
d4bc8dc0 105static void
18c8241a
MM
106slab_dump(resource *r)
107{
108 slab *s = (slab *) r;
109 int cnt = 0;
110 struct sl_obj *o;
111
112 WALK_LIST(o, s->objs)
113 cnt++;
114 debug("(%d objects per %d bytes)\n", cnt, s->size);
115}
35496679
MM
116
117#else
118
119/*
120 * Real efficient version.
121 */
122
123#define SLAB_SIZE 4096
124#define MAX_EMPTY_HEADS 1
125
126struct slab {
127 resource r;
be77b689 128 unsigned obj_size, head_size, objs_per_slab, num_empty_heads, data_size;
35496679
MM
129 list empty_heads, partial_heads, full_heads;
130};
131
132static struct resclass sl_class = {
133 "Slab",
134 sizeof(struct slab),
135 slab_free,
c9763428
MM
136 slab_dump,
137 slab_lookup
35496679
MM
138};
139
140struct sl_head {
141 node n;
142 struct sl_obj *first_free;
143 int num_full;
144};
145
146struct sl_obj {
147 struct sl_head *slab;
148 union {
149 struct sl_obj *next;
150 byte data[0];
151 } u;
152};
153
154struct sl_alignment { /* Magic structure for testing of alignment */
155 byte data;
156 int x[0];
157};
158
5cc1e1f8
MM
159/**
160 * sl_new - create a new Slab
161 * @p: resource pool
162 * @size: block size
163 *
164 * This function creates a new Slab resource from which
165 * objects of size @size can be allocated.
166 */
35496679
MM
167slab *
168sl_new(pool *p, unsigned size)
169{
170 slab *s = ralloc(p, &sl_class);
171 unsigned int align = sizeof(struct sl_alignment);
172 if (align < sizeof(int))
173 align = sizeof(int);
be77b689 174 s->data_size = size;
35496679
MM
175 size += OFFSETOF(struct sl_obj, u.data);
176 if (size < sizeof(struct sl_obj))
177 size = sizeof(struct sl_obj);
178 size = (size + align - 1) / align * align;
179 s->obj_size = size;
180 s->head_size = (sizeof(struct sl_head) + align - 1) / align * align;
181 s->objs_per_slab = (SLAB_SIZE - s->head_size) / size;
182 if (!s->objs_per_slab)
183 bug("Slab: object too large");
184 s->num_empty_heads = 0;
185 init_list(&s->empty_heads);
186 init_list(&s->partial_heads);
187 init_list(&s->full_heads);
188 return s;
189}
190
9831e591 191static struct sl_head *
35496679
MM
192sl_new_head(slab *s)
193{
194 struct sl_head *h = xmalloc(SLAB_SIZE);
195 struct sl_obj *o = (struct sl_obj *)((byte *)h+s->head_size);
196 struct sl_obj *no;
197 unsigned int n = s->objs_per_slab;
198
199 h->first_free = o;
200 h->num_full = 0;
201 while (n--)
202 {
203 o->slab = h;
204 no = (struct sl_obj *)((char *) o+s->obj_size);
205 o->u.next = n ? no : NULL;
206 o = no;
207 }
208 return h;
209}
210
5cc1e1f8
MM
211/**
212 * sl_alloc - allocate an object from Slab
213 * @s: slab
214 *
215 * sl_alloc() allocates space for a single object from the
216 * Slab and returns a pointer to the object.
217 */
35496679
MM
218void *
219sl_alloc(slab *s)
220{
221 struct sl_head *h;
222 struct sl_obj *o;
223
224redo:
225 h = HEAD(s->partial_heads);
226 if (!h->n.next)
227 goto no_partial;
228okay:
229 o = h->first_free;
230 if (!o)
231 goto full_partial;
232 h->first_free = o->u.next;
233 h->num_full++;
be77b689
MM
234#ifdef POISON
235 memset(o->u.data, 0xcd, s->data_size);
236#endif
35496679
MM
237 return o->u.data;
238
239full_partial:
240 rem_node(&h->n);
241 add_tail(&s->full_heads, &h->n);
242 goto redo;
243
244no_partial:
245 h = HEAD(s->empty_heads);
246 if (h->n.next)
247 {
248 rem_node(&h->n);
249 add_head(&s->partial_heads, &h->n);
250 s->num_empty_heads--;
251 goto okay;
252 }
253 h = sl_new_head(s);
254 add_head(&s->partial_heads, &h->n);
255 goto okay;
256}
257
5cc1e1f8
MM
258/**
259 * sl_free - return a free object back to a Slab
260 * @s: slab
261 * @oo: object returned by sl_alloc()
262 *
263 * This function frees memory associated with the object @oo
264 * and returns it back to the Slab @s.
265 */
35496679
MM
266void
267sl_free(slab *s, void *oo)
268{
269 struct sl_obj *o = SKIP_BACK(struct sl_obj, u.data, oo);
270 struct sl_head *h = o->slab;
271
b8e60d35 272#ifdef POISON
be77b689 273 memset(oo, 0xdb, s->data_size);
b8e60d35 274#endif
35496679
MM
275 o->u.next = h->first_free;
276 h->first_free = o;
277 if (!--h->num_full)
278 {
279 rem_node(&h->n);
280 if (s->num_empty_heads >= MAX_EMPTY_HEADS)
281 xfree(h);
282 else
283 {
284 add_head(&s->empty_heads, &h->n);
285 s->num_empty_heads++;
286 }
287 }
288 else if (!o->u.next)
289 {
290 rem_node(&h->n);
291 add_head(&s->partial_heads, &h->n);
292 }
293}
294
295static void
296slab_free(resource *r)
297{
298 slab *s = (slab *) r;
299 struct sl_head *h, *g;
300
301 WALK_LIST_DELSAFE(h, g, s->empty_heads)
302 xfree(h);
303 WALK_LIST_DELSAFE(h, g, s->partial_heads)
304 xfree(h);
305 WALK_LIST_DELSAFE(h, g, s->full_heads)
306 xfree(h);
307}
308
309static void
310slab_dump(resource *r)
311{
312 slab *s = (slab *) r;
313 int ec=0, pc=0, fc=0;
314 struct sl_head *h;
315
316 WALK_LIST(h, s->empty_heads)
317 ec++;
318 WALK_LIST(h, s->partial_heads)
319 pc++;
320 WALK_LIST(h, s->full_heads)
321 fc++;
322 debug("(%de+%dp+%df blocks per %d objs per %d bytes)\n", ec, pc, fc, s->objs_per_slab, s->obj_size);
323}
324
c9763428
MM
325static resource *
326slab_lookup(resource *r, unsigned long a)
327{
328 slab *s = (slab *) r;
329 struct sl_head *h;
330
331 WALK_LIST(h, s->partial_heads)
332 if ((unsigned long) h < a && (unsigned long) h + SLAB_SIZE < a)
333 return r;
334 WALK_LIST(h, s->full_heads)
335 if ((unsigned long) h < a && (unsigned long) h + SLAB_SIZE < a)
336 return r;
337 return NULL;
338}
339
35496679 340#endif