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>