Annotation of embedaddon/bird/lib/mempool.c, revision 1.1.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.
                     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: struct linpool {
                     36:   resource r;
                     37:   byte *ptr, *end;
                     38:   struct lp_chunk *first, *current, **plast;   /* Normal (reusable) chunks */
                     39:   struct lp_chunk *first_large;                        /* Large chunks */
                     40:   uint chunk_size, threshold, total, total_large;
                     41: };
                     42: 
                     43: static void lp_free(resource *);
                     44: static void lp_dump(resource *);
                     45: static resource *lp_lookup(resource *, unsigned long);
                     46: static size_t lp_memsize(resource *r);
                     47: 
                     48: static struct resclass lp_class = {
                     49:   "LinPool",
                     50:   sizeof(struct linpool),
                     51:   lp_free,
                     52:   lp_dump,
                     53:   lp_lookup,
                     54:   lp_memsize
                     55: };
                     56: 
                     57: /**
                     58:  * lp_new - create a new linear memory pool
                     59:  * @p: pool
                     60:  * @blk: block size
                     61:  *
                     62:  * lp_new() creates a new linear memory pool resource inside the pool @p.
                     63:  * The linear pool consists of a list of memory chunks of size at least
                     64:  * @blk.
                     65:  */
                     66: linpool
                     67: *lp_new(pool *p, uint blk)
                     68: {
                     69:   linpool *m = ralloc(p, &lp_class);
                     70:   m->plast = &m->first;
                     71:   m->chunk_size = blk;
                     72:   m->threshold = 3*blk/4;
                     73:   return m;
                     74: }
                     75: 
                     76: /**
                     77:  * lp_alloc - allocate memory from a &linpool
                     78:  * @m: linear memory pool
                     79:  * @size: amount of memory
                     80:  *
                     81:  * lp_alloc() allocates @size bytes of memory from a &linpool @m
                     82:  * and it returns a pointer to the allocated memory.
                     83:  *
                     84:  * It works by trying to find free space in the last memory chunk
                     85:  * associated with the &linpool and creating a new chunk of the standard
                     86:  * size (as specified during lp_new()) if the free space is too small
                     87:  * to satisfy the allocation. If @size is too large to fit in a standard
                     88:  * size chunk, an "overflow" chunk is created for it instead.
                     89:  */
                     90: void *
                     91: lp_alloc(linpool *m, uint size)
                     92: {
                     93:   byte *a = (byte *) BIRD_ALIGN((unsigned long) m->ptr, CPU_STRUCT_ALIGN);
                     94:   byte *e = a + size;
                     95: 
                     96:   if (e <= m->end)
                     97:     {
                     98:       m->ptr = e;
                     99:       return a;
                    100:     }
                    101:   else
                    102:     {
                    103:       struct lp_chunk *c;
                    104:       if (size >= m->threshold)
                    105:        {
                    106:          /* Too large => allocate large chunk */
                    107:          c = xmalloc(sizeof(struct lp_chunk) + size);
                    108:          m->total_large += size;
                    109:          c->next = m->first_large;
                    110:          m->first_large = c;
                    111:          c->size = size;
                    112:        }
                    113:       else
                    114:        {
                    115:          if (m->current)
                    116:            {
                    117:              /* Still have free chunks from previous incarnation (before lp_flush()) */
                    118:              c = m->current;
                    119:              m->current = c->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:              *m->plast = c;
                    127:              m->plast = &c->next;
                    128:              c->next = NULL;
                    129:              c->size = m->chunk_size;
                    130:            }
                    131:          m->ptr = c->data + size;
                    132:          m->end = c->data + m->chunk_size;
                    133:        }
                    134:       return c->data;
                    135:     }
                    136: }
                    137: 
                    138: /**
                    139:  * lp_allocu - allocate unaligned memory from a &linpool
                    140:  * @m: linear memory pool
                    141:  * @size: amount of memory
                    142:  *
                    143:  * lp_allocu() allocates @size bytes of memory from a &linpool @m
                    144:  * and it returns a pointer to the allocated memory. It doesn't
                    145:  * attempt to align the memory block, giving a very efficient way
                    146:  * how to allocate strings without any space overhead.
                    147:  */
                    148: void *
                    149: lp_allocu(linpool *m, uint size)
                    150: {
                    151:   byte *a = m->ptr;
                    152:   byte *e = a + size;
                    153: 
                    154:   if (e <= m->end)
                    155:     {
                    156:       m->ptr = e;
                    157:       return a;
                    158:     }
                    159:   return lp_alloc(m, size);
                    160: }
                    161: 
                    162: /**
                    163:  * lp_allocz - allocate cleared memory from a &linpool
                    164:  * @m: linear memory pool
                    165:  * @size: amount of memory
                    166:  *
                    167:  * This function is identical to lp_alloc() except that it
                    168:  * clears the allocated memory block.
                    169:  */
                    170: void *
                    171: lp_allocz(linpool *m, uint size)
                    172: {
                    173:   void *z = lp_alloc(m, size);
                    174: 
                    175:   bzero(z, size);
                    176:   return z;
                    177: }
                    178: 
                    179: /**
                    180:  * lp_flush - flush a linear memory pool
                    181:  * @m: linear memory pool
                    182:  *
                    183:  * This function frees the whole contents of the given &linpool @m,
                    184:  * but leaves the pool itself.
                    185:  */
                    186: void
                    187: lp_flush(linpool *m)
                    188: {
                    189:   struct lp_chunk *c;
                    190: 
                    191:   /* Relink all normal chunks to free list and free all large chunks */
                    192:   m->ptr = m->end = NULL;
                    193:   m->current = m->first;
                    194:   while (c = m->first_large)
                    195:     {
                    196:       m->first_large = c->next;
                    197:       xfree(c);
                    198:     }
                    199:   m->total_large = 0;
                    200: }
                    201: 
                    202: static void
                    203: lp_free(resource *r)
                    204: {
                    205:   linpool *m = (linpool *) r;
                    206:   struct lp_chunk *c, *d;
                    207: 
                    208:   for(d=m->first; d; d = c)
                    209:     {
                    210:       c = d->next;
                    211:       xfree(d);
                    212:     }
                    213:   for(d=m->first_large; d; d = c)
                    214:     {
                    215:       c = d->next;
                    216:       xfree(d);
                    217:     }
                    218: }
                    219: 
                    220: static void
                    221: lp_dump(resource *r)
                    222: {
                    223:   linpool *m = (linpool *) r;
                    224:   struct lp_chunk *c;
                    225:   int cnt, cntl;
                    226: 
                    227:   for(cnt=0, c=m->first; c; c=c->next, cnt++)
                    228:     ;
                    229:   for(cntl=0, c=m->first_large; c; c=c->next, cntl++)
                    230:     ;
                    231:   debug("(chunk=%d threshold=%d count=%d+%d total=%d+%d)\n",
                    232:        m->chunk_size,
                    233:        m->threshold,
                    234:        cnt,
                    235:        cntl,
                    236:        m->total,
                    237:        m->total_large);
                    238: }
                    239: 
                    240: static size_t
                    241: lp_memsize(resource *r)
                    242: {
                    243:   linpool *m = (linpool *) r;
                    244:   struct lp_chunk *c;
                    245:   int cnt = 0;
                    246: 
                    247:   for(c=m->first; c; c=c->next)
                    248:     cnt++;
                    249:   for(c=m->first_large; c; c=c->next)
                    250:     cnt++;
                    251: 
                    252:   return ALLOC_OVERHEAD + sizeof(struct linpool) +
                    253:     cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)) +
                    254:     m->total + m->total_large;
                    255: }
                    256: 
                    257: 
                    258: static resource *
                    259: lp_lookup(resource *r, unsigned long a)
                    260: {
                    261:   linpool *m = (linpool *) r;
                    262:   struct lp_chunk *c;
                    263: 
                    264:   for(c=m->first; c; c=c->next)
                    265:     if ((unsigned long) c->data <= a && (unsigned long) c->data + c->size > a)
                    266:       return r;
                    267:   for(c=m->first_large; c; c=c->next)
                    268:     if ((unsigned long) c->data <= a && (unsigned long) c->data + c->size > a)
                    269:       return r;
                    270:   return NULL;
                    271: }

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