Annotation of embedaddon/bird/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.
! 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>