Annotation of embedaddon/bird2/lib/mempool.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD Resource Manager -- Memory Pools
        !             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: /**
        !            10:  * DOC: Linear memory pools
        !            11:  *
        !            12:  * Linear memory pools are collections of memory blocks which
        !            13:  * support very fast allocation of new blocks, but are able to free only
        !            14:  * the whole collection at once (or in stack order).
        !            15:  *
        !            16:  * Example: Each configuration is described by a complex system of structures,
        !            17:  * linked lists and function trees which are all allocated from a single linear
        !            18:  * pool, thus they can be freed at once when the configuration is no longer used.
        !            19:  */
        !            20: 
        !            21: #include <stdlib.h>
        !            22: #include <stdint.h>
        !            23: 
        !            24: #include "nest/bird.h"
        !            25: #include "lib/resource.h"
        !            26: #include "lib/string.h"
        !            27: 
        !            28: struct lp_chunk {
        !            29:   struct lp_chunk *next;
        !            30:   uint size;
        !            31:   uintptr_t data_align[0];
        !            32:   byte data[0];
        !            33: };
        !            34: 
        !            35: const int lp_chunk_size = sizeof(struct lp_chunk);
        !            36: 
        !            37: struct linpool {
        !            38:   resource r;
        !            39:   byte *ptr, *end;
        !            40:   struct lp_chunk *first, *current;            /* Normal (reusable) chunks */
        !            41:   struct lp_chunk *first_large;                        /* Large chunks */
        !            42:   uint chunk_size, threshold, total, total_large;
        !            43: };
        !            44: 
        !            45: static void lp_free(resource *);
        !            46: static void lp_dump(resource *);
        !            47: static resource *lp_lookup(resource *, unsigned long);
        !            48: static size_t lp_memsize(resource *r);
        !            49: 
        !            50: static struct resclass lp_class = {
        !            51:   "LinPool",
        !            52:   sizeof(struct linpool),
        !            53:   lp_free,
        !            54:   lp_dump,
        !            55:   lp_lookup,
        !            56:   lp_memsize
        !            57: };
        !            58: 
        !            59: /**
        !            60:  * lp_new - create a new linear memory pool
        !            61:  * @p: pool
        !            62:  * @blk: block size
        !            63:  *
        !            64:  * lp_new() creates a new linear memory pool resource inside the pool @p.
        !            65:  * The linear pool consists of a list of memory chunks of size at least
        !            66:  * @blk.
        !            67:  */
        !            68: linpool
        !            69: *lp_new(pool *p, uint blk)
        !            70: {
        !            71:   linpool *m = ralloc(p, &lp_class);
        !            72:   m->chunk_size = blk;
        !            73:   m->threshold = 3*blk/4;
        !            74:   return m;
        !            75: }
        !            76: 
        !            77: /**
        !            78:  * lp_alloc - allocate memory from a &linpool
        !            79:  * @m: linear memory pool
        !            80:  * @size: amount of memory
        !            81:  *
        !            82:  * lp_alloc() allocates @size bytes of memory from a &linpool @m
        !            83:  * and it returns a pointer to the allocated memory.
        !            84:  *
        !            85:  * It works by trying to find free space in the last memory chunk
        !            86:  * associated with the &linpool and creating a new chunk of the standard
        !            87:  * size (as specified during lp_new()) if the free space is too small
        !            88:  * to satisfy the allocation. If @size is too large to fit in a standard
        !            89:  * size chunk, an "overflow" chunk is created for it instead.
        !            90:  */
        !            91: void *
        !            92: lp_alloc(linpool *m, uint size)
        !            93: {
        !            94:   byte *a = (byte *) BIRD_ALIGN((unsigned long) m->ptr, CPU_STRUCT_ALIGN);
        !            95:   byte *e = a + size;
        !            96: 
        !            97:   if (e <= m->end)
        !            98:     {
        !            99:       m->ptr = e;
        !           100:       return a;
        !           101:     }
        !           102:   else
        !           103:     {
        !           104:       struct lp_chunk *c;
        !           105:       if (size >= m->threshold)
        !           106:        {
        !           107:          /* Too large => allocate large chunk */
        !           108:          c = xmalloc(sizeof(struct lp_chunk) + size);
        !           109:          m->total_large += size;
        !           110:          c->next = m->first_large;
        !           111:          m->first_large = c;
        !           112:          c->size = size;
        !           113:        }
        !           114:       else
        !           115:        {
        !           116:          if (m->current && m->current->next)
        !           117:            {
        !           118:              /* Still have free chunks from previous incarnation (before lp_flush()) */
        !           119:              c = m->current->next;
        !           120:            }
        !           121:          else
        !           122:            {
        !           123:              /* Need to allocate a new chunk */
        !           124:              c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
        !           125:              m->total += m->chunk_size;
        !           126:              c->next = NULL;
        !           127:              c->size = m->chunk_size;
        !           128: 
        !           129:              if (m->current)
        !           130:                m->current->next = c;
        !           131:              else
        !           132:                m->first = c;
        !           133:            }
        !           134:          m->current = c;
        !           135:          m->ptr = c->data + size;
        !           136:          m->end = c->data + m->chunk_size;
        !           137:        }
        !           138:       return c->data;
        !           139:     }
        !           140: }
        !           141: 
        !           142: /**
        !           143:  * lp_allocu - allocate unaligned memory from a &linpool
        !           144:  * @m: linear memory pool
        !           145:  * @size: amount of memory
        !           146:  *
        !           147:  * lp_allocu() allocates @size bytes of memory from a &linpool @m
        !           148:  * and it returns a pointer to the allocated memory. It doesn't
        !           149:  * attempt to align the memory block, giving a very efficient way
        !           150:  * how to allocate strings without any space overhead.
        !           151:  */
        !           152: void *
        !           153: lp_allocu(linpool *m, uint size)
        !           154: {
        !           155:   byte *a = m->ptr;
        !           156:   byte *e = a + size;
        !           157: 
        !           158:   if (e <= m->end)
        !           159:     {
        !           160:       m->ptr = e;
        !           161:       return a;
        !           162:     }
        !           163:   return lp_alloc(m, size);
        !           164: }
        !           165: 
        !           166: /**
        !           167:  * lp_allocz - allocate cleared memory from a &linpool
        !           168:  * @m: linear memory pool
        !           169:  * @size: amount of memory
        !           170:  *
        !           171:  * This function is identical to lp_alloc() except that it
        !           172:  * clears the allocated memory block.
        !           173:  */
        !           174: void *
        !           175: lp_allocz(linpool *m, uint size)
        !           176: {
        !           177:   void *z = lp_alloc(m, size);
        !           178: 
        !           179:   bzero(z, size);
        !           180:   return z;
        !           181: }
        !           182: 
        !           183: /**
        !           184:  * lp_flush - flush a linear memory pool
        !           185:  * @m: linear memory pool
        !           186:  *
        !           187:  * This function frees the whole contents of the given &linpool @m,
        !           188:  * but leaves the pool itself.
        !           189:  */
        !           190: void
        !           191: lp_flush(linpool *m)
        !           192: {
        !           193:   struct lp_chunk *c;
        !           194: 
        !           195:   /* Move ptr to the first chunk and free all large chunks */
        !           196:   m->current = c = m->first;
        !           197:   m->ptr = c ? c->data : NULL;
        !           198:   m->end = c ? c->data + m->chunk_size : NULL;
        !           199: 
        !           200:   while (c = m->first_large)
        !           201:     {
        !           202:       m->first_large = c->next;
        !           203:       xfree(c);
        !           204:     }
        !           205:   m->total_large = 0;
        !           206: }
        !           207: 
        !           208: /**
        !           209:  * lp_save - save the state of a linear memory pool
        !           210:  * @m: linear memory pool
        !           211:  * @p: state buffer
        !           212:  *
        !           213:  * This function saves the state of a linear memory pool. Saved state can be
        !           214:  * used later to restore the pool (to free memory allocated since).
        !           215:  */
        !           216: void
        !           217: lp_save(linpool *m, lp_state *p)
        !           218: {
        !           219:   p->current = m->current;
        !           220:   p->large = m->first_large;
        !           221:   p->ptr = m->ptr;
        !           222: }
        !           223: 
        !           224: /**
        !           225:  * lp_restore - restore the state of a linear memory pool
        !           226:  * @m: linear memory pool
        !           227:  * @p: saved state
        !           228:  *
        !           229:  * This function restores the state of a linear memory pool, freeing all memory
        !           230:  * allocated since the state was saved. Note that the function cannot un-free
        !           231:  * the memory, therefore the function also invalidates other states that were
        !           232:  * saved between (on the same pool).
        !           233:  */
        !           234: void
        !           235: lp_restore(linpool *m, lp_state *p)
        !           236: {
        !           237:   struct lp_chunk *c;
        !           238: 
        !           239:   /* Move ptr to the saved pos and free all newer large chunks */
        !           240:   m->current = c = p->current;
        !           241:   m->ptr = p->ptr;
        !           242:   m->end = c ? c->data + m->chunk_size : NULL;
        !           243: 
        !           244:   while ((c = m->first_large) && (c != p->large))
        !           245:     {
        !           246:       m->first_large = c->next;
        !           247:       m->total_large -= c->size;
        !           248:       xfree(c);
        !           249:     }
        !           250: }
        !           251: 
        !           252: static void
        !           253: lp_free(resource *r)
        !           254: {
        !           255:   linpool *m = (linpool *) r;
        !           256:   struct lp_chunk *c, *d;
        !           257: 
        !           258:   for(d=m->first; d; d = c)
        !           259:     {
        !           260:       c = d->next;
        !           261:       xfree(d);
        !           262:     }
        !           263:   for(d=m->first_large; d; d = c)
        !           264:     {
        !           265:       c = d->next;
        !           266:       xfree(d);
        !           267:     }
        !           268: }
        !           269: 
        !           270: static void
        !           271: lp_dump(resource *r)
        !           272: {
        !           273:   linpool *m = (linpool *) r;
        !           274:   struct lp_chunk *c;
        !           275:   int cnt, cntl;
        !           276: 
        !           277:   for(cnt=0, c=m->first; c; c=c->next, cnt++)
        !           278:     ;
        !           279:   for(cntl=0, c=m->first_large; c; c=c->next, cntl++)
        !           280:     ;
        !           281:   debug("(chunk=%d threshold=%d count=%d+%d total=%d+%d)\n",
        !           282:        m->chunk_size,
        !           283:        m->threshold,
        !           284:        cnt,
        !           285:        cntl,
        !           286:        m->total,
        !           287:        m->total_large);
        !           288: }
        !           289: 
        !           290: static size_t
        !           291: lp_memsize(resource *r)
        !           292: {
        !           293:   linpool *m = (linpool *) r;
        !           294:   struct lp_chunk *c;
        !           295:   int cnt = 0;
        !           296: 
        !           297:   for(c=m->first; c; c=c->next)
        !           298:     cnt++;
        !           299:   for(c=m->first_large; c; c=c->next)
        !           300:     cnt++;
        !           301: 
        !           302:   return ALLOC_OVERHEAD + sizeof(struct linpool) +
        !           303:     cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)) +
        !           304:     m->total + m->total_large;
        !           305: }
        !           306: 
        !           307: 
        !           308: static resource *
        !           309: lp_lookup(resource *r, unsigned long a)
        !           310: {
        !           311:   linpool *m = (linpool *) r;
        !           312:   struct lp_chunk *c;
        !           313: 
        !           314:   for(c=m->first; c; c=c->next)
        !           315:     if ((unsigned long) c->data <= a && (unsigned long) c->data + c->size > a)
        !           316:       return r;
        !           317:   for(c=m->first_large; c; c=c->next)
        !           318:     if ((unsigned long) c->data <= a && (unsigned long) c->data + c->size > a)
        !           319:       return r;
        !           320:   return NULL;
        !           321: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>