Annotation of embedaddon/bird2/lib/resource.c, revision 1.1.1.1
1.1 misho 1: /*
2: * BIRD Resource Manager
3: *
4: * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5: *
6: * Can be freely distributed and used under the terms of the GNU GPL.
7: */
8:
9: #include <stdio.h>
10: #include <stdlib.h>
11: #include <stdint.h>
12:
13: #include "nest/bird.h"
14: #include "lib/resource.h"
15: #include "lib/string.h"
16:
17: /**
18: * DOC: Resource pools
19: *
20: * Resource pools (&pool) are just containers holding a list of
21: * other resources. Freeing a pool causes all the listed resources
22: * to be freed as well. Each existing &resource is linked to some pool
23: * except for a root pool which isn't linked anywhere, so all the
24: * resources form a tree structure with internal nodes corresponding
25: * to pools and leaves being the other resources.
26: *
27: * Example: Almost all modules of BIRD have their private pool which
28: * is freed upon shutdown of the module.
29: */
30:
31: struct pool {
32: resource r;
33: list inside;
34: const char *name;
35: };
36:
37: static void pool_dump(resource *);
38: static void pool_free(resource *);
39: static resource *pool_lookup(resource *, unsigned long);
40: static size_t pool_memsize(resource *P);
41:
42: static struct resclass pool_class = {
43: "Pool",
44: sizeof(pool),
45: pool_free,
46: pool_dump,
47: pool_lookup,
48: pool_memsize
49: };
50:
51: pool root_pool;
52:
53: static int indent;
54:
55: /**
56: * rp_new - create a resource pool
57: * @p: parent pool
58: * @name: pool name (to be included in debugging dumps)
59: *
60: * rp_new() creates a new resource pool inside the specified
61: * parent pool.
62: */
63: pool *
64: rp_new(pool *p, const char *name)
65: {
66: pool *z = ralloc(p, &pool_class);
67: z->name = name;
68: init_list(&z->inside);
69: return z;
70: }
71:
72: static void
73: pool_free(resource *P)
74: {
75: pool *p = (pool *) P;
76: resource *r, *rr;
77:
78: r = HEAD(p->inside);
79: while (rr = (resource *) r->n.next)
80: {
81: r->class->free(r);
82: xfree(r);
83: r = rr;
84: }
85: }
86:
87: static void
88: pool_dump(resource *P)
89: {
90: pool *p = (pool *) P;
91: resource *r;
92:
93: debug("%s\n", p->name);
94: indent += 3;
95: WALK_LIST(r, p->inside)
96: rdump(r);
97: indent -= 3;
98: }
99:
100: static size_t
101: pool_memsize(resource *P)
102: {
103: pool *p = (pool *) P;
104: resource *r;
105: size_t sum = sizeof(pool) + ALLOC_OVERHEAD;
106:
107: WALK_LIST(r, p->inside)
108: sum += rmemsize(r);
109:
110: return sum;
111: }
112:
113: static resource *
114: pool_lookup(resource *P, unsigned long a)
115: {
116: pool *p = (pool *) P;
117: resource *r, *q;
118:
119: WALK_LIST(r, p->inside)
120: if (r->class->lookup && (q = r->class->lookup(r, a)))
121: return q;
122: return NULL;
123: }
124:
125: /**
126: * rmove - move a resource
127: * @res: resource
128: * @p: pool to move the resource to
129: *
130: * rmove() moves a resource from one pool to another.
131: */
132:
133: void rmove(void *res, pool *p)
134: {
135: resource *r = res;
136:
137: if (r)
138: {
139: if (r->n.next)
140: rem_node(&r->n);
141: add_tail(&p->inside, &r->n);
142: }
143: }
144:
145: /**
146: * rfree - free a resource
147: * @res: resource
148: *
149: * rfree() frees the given resource and all information associated
150: * with it. In case it's a resource pool, it also frees all the objects
151: * living inside the pool.
152: *
153: * It works by calling a class-specific freeing function.
154: */
155: void
156: rfree(void *res)
157: {
158: resource *r = res;
159:
160: if (!r)
161: return;
162:
163: if (r->n.next)
164: rem_node(&r->n);
165: r->class->free(r);
166: r->class = NULL;
167: xfree(r);
168: }
169:
170: /**
171: * rdump - dump a resource
172: * @res: resource
173: *
174: * This function prints out all available information about the given
175: * resource to the debugging output.
176: *
177: * It works by calling a class-specific dump function.
178: */
179: void
180: rdump(void *res)
181: {
182: char x[16];
183: resource *r = res;
184:
185: bsprintf(x, "%%%ds%%p ", indent);
186: debug(x, "", r);
187: if (r)
188: {
189: debug("%s ", r->class->name);
190: r->class->dump(r);
191: }
192: else
193: debug("NULL\n");
194: }
195:
196: size_t
197: rmemsize(void *res)
198: {
199: resource *r = res;
200: if (!r)
201: return 0;
202: if (!r->class->memsize)
203: return r->class->size + ALLOC_OVERHEAD;
204: return r->class->memsize(r);
205: }
206:
207: /**
208: * ralloc - create a resource
209: * @p: pool to create the resource in
210: * @c: class of the new resource
211: *
212: * This function is called by the resource classes to create a new
213: * resource of the specified class and link it to the given pool.
214: * Allocated memory is zeroed. Size of the resource structure is taken
215: * from the @size field of the &resclass.
216: */
217: void *
218: ralloc(pool *p, struct resclass *c)
219: {
220: resource *r = xmalloc(c->size);
221: bzero(r, c->size);
222:
223: r->class = c;
224: if (p)
225: add_tail(&p->inside, &r->n);
226: return r;
227: }
228:
229: /**
230: * rlookup - look up a memory location
231: * @a: memory address
232: *
233: * This function examines all existing resources to see whether
234: * the address @a is inside any resource. It's used for debugging
235: * purposes only.
236: *
237: * It works by calling a class-specific lookup function for each
238: * resource.
239: */
240: void
241: rlookup(unsigned long a)
242: {
243: resource *r;
244:
245: debug("Looking up %08lx\n", a);
246: if (r = pool_lookup(&root_pool.r, a))
247: rdump(r);
248: else
249: debug("Not found.\n");
250: }
251:
252: /**
253: * resource_init - initialize the resource manager
254: *
255: * This function is called during BIRD startup. It initializes
256: * all data structures of the resource manager and creates the
257: * root pool.
258: */
259: void
260: resource_init(void)
261: {
262: root_pool.r.class = &pool_class;
263: root_pool.name = "Root";
264: init_list(&root_pool.inside);
265: }
266:
267: /**
268: * DOC: Memory blocks
269: *
270: * Memory blocks are pieces of contiguous allocated memory.
271: * They are a bit non-standard since they are represented not by a pointer
272: * to &resource, but by a void pointer to the start of data of the
273: * memory block. All memory block functions know how to locate the header
274: * given the data pointer.
275: *
276: * Example: All "unique" data structures such as hash tables are allocated
277: * as memory blocks.
278: */
279:
280: struct mblock {
281: resource r;
282: unsigned size;
283: uintptr_t data_align[0];
284: byte data[0];
285: };
286:
287: static void mbl_free(resource *r UNUSED)
288: {
289: }
290:
291: static void mbl_debug(resource *r)
292: {
293: struct mblock *m = (struct mblock *) r;
294:
295: debug("(size=%d)\n", m->size);
296: }
297:
298: static resource *
299: mbl_lookup(resource *r, unsigned long a)
300: {
301: struct mblock *m = (struct mblock *) r;
302:
303: if ((unsigned long) m->data <= a && (unsigned long) m->data + m->size > a)
304: return r;
305: return NULL;
306: }
307:
308: static size_t
309: mbl_memsize(resource *r)
310: {
311: struct mblock *m = (struct mblock *) r;
312: return ALLOC_OVERHEAD + sizeof(struct mblock) + m->size;
313: }
314:
315: static struct resclass mb_class = {
316: "Memory",
317: 0,
318: mbl_free,
319: mbl_debug,
320: mbl_lookup,
321: mbl_memsize
322: };
323:
324: /**
325: * mb_alloc - allocate a memory block
326: * @p: pool
327: * @size: size of the block
328: *
329: * mb_alloc() allocates memory of a given size and creates
330: * a memory block resource representing this memory chunk
331: * in the pool @p.
332: *
333: * Please note that mb_alloc() returns a pointer to the memory
334: * chunk, not to the resource, hence you have to free it using
335: * mb_free(), not rfree().
336: */
337: void *
338: mb_alloc(pool *p, unsigned size)
339: {
340: struct mblock *b = xmalloc(sizeof(struct mblock) + size);
341:
342: b->r.class = &mb_class;
343: add_tail(&p->inside, &b->r.n);
344: b->size = size;
345: return b->data;
346: }
347:
348: /**
349: * mb_allocz - allocate and clear a memory block
350: * @p: pool
351: * @size: size of the block
352: *
353: * mb_allocz() allocates memory of a given size, initializes it to
354: * zeroes and creates a memory block resource representing this memory
355: * chunk in the pool @p.
356: *
357: * Please note that mb_allocz() returns a pointer to the memory
358: * chunk, not to the resource, hence you have to free it using
359: * mb_free(), not rfree().
360: */
361: void *
362: mb_allocz(pool *p, unsigned size)
363: {
364: void *x = mb_alloc(p, size);
365: bzero(x, size);
366: return x;
367: }
368:
369: /**
370: * mb_realloc - reallocate a memory block
371: * @m: memory block
372: * @size: new size of the block
373: *
374: * mb_realloc() changes the size of the memory block @m to a given size.
375: * The contents will be unchanged to the minimum of the old and new sizes;
376: * newly allocated memory will be uninitialized. Contrary to realloc()
377: * behavior, @m must be non-NULL, because the resource pool is inherited
378: * from it.
379: *
380: * Like mb_alloc(), mb_realloc() also returns a pointer to the memory
381: * chunk, not to the resource, hence you have to free it using
382: * mb_free(), not rfree().
383: */
384: void *
385: mb_realloc(void *m, unsigned size)
386: {
387: struct mblock *b = SKIP_BACK(struct mblock, data, m);
388:
389: b = xrealloc(b, sizeof(struct mblock) + size);
390: replace_node(&b->r.n, &b->r.n);
391: b->size = size;
392: return b->data;
393: }
394:
395:
396: /**
397: * mb_free - free a memory block
398: * @m: memory block
399: *
400: * mb_free() frees all memory associated with the block @m.
401: */
402: void
403: mb_free(void *m)
404: {
405: if (!m)
406: return;
407:
408: struct mblock *b = SKIP_BACK(struct mblock, data, m);
409: rfree(b);
410: }
411:
412:
413:
414: #define STEP_UP(x) ((x) + (x)/2 + 4)
415:
416: void
417: buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_size)
418: {
419: unsigned nsize = MIN(*size, need);
420:
421: while (nsize < need)
422: nsize = STEP_UP(nsize);
423:
424: *buf = mb_realloc(*buf, nsize * item_size);
425: *size = nsize;
426: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>