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