Annotation of embedaddon/bird2/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 (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>