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>