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>