File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / lib / resource.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Aug 22 12:33:54 2017 UTC (6 years, 10 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, v1_6_3p0, v1_6_3, HEAD
bird 1.6.3

    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>