Annotation of embedaddon/bird/lib/resource.c, revision 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: 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, 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>