]>
git.ipfire.org Git - thirdparty/bird.git/blob - lib/mempool.c
2 * BIRD Resource Manager -- Memory Pools
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
10 * DOC: Linear memory pools
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).
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.
24 #include "nest/bird.h"
25 #include "lib/resource.h"
26 #include "lib/string.h"
29 struct lp_chunk
*next
;
31 uintptr_t data_align
[0];
35 const int lp_chunk_size
= sizeof(struct lp_chunk
);
41 struct lp_chunk
*first
, *current
; /* Normal (reusable) chunks */
42 struct lp_chunk
*first_large
; /* Large chunks */
43 uint chunk_size
, threshold
, total
:31, use_pages
:1, total_large
;
46 _Thread_local linpool
*tmp_linpool
;
48 static void lp_free(resource
*);
49 static void lp_dump(resource
*);
50 static resource
*lp_lookup(resource
*, unsigned long);
51 static struct resmem
lp_memsize(resource
*r
);
53 static struct resclass lp_class
= {
55 sizeof(struct linpool
),
63 * lp_new - create a new linear memory pool
67 * lp_new() creates a new linear memory pool resource inside the pool @p.
68 * The linear pool consists of a list of memory chunks of size at least
72 *lp_new(pool
*p
, uint blk
)
74 linpool
*m
= ralloc(p
, &lp_class
);
79 blk
= page_size
- lp_chunk_size
;
83 m
->threshold
= 3*blk
/4;
88 * lp_alloc - allocate memory from a &linpool
89 * @m: linear memory pool
90 * @size: amount of memory
92 * lp_alloc() allocates @size bytes of memory from a &linpool @m
93 * and it returns a pointer to the allocated memory.
95 * It works by trying to find free space in the last memory chunk
96 * associated with the &linpool and creating a new chunk of the standard
97 * size (as specified during lp_new()) if the free space is too small
98 * to satisfy the allocation. If @size is too large to fit in a standard
99 * size chunk, an "overflow" chunk is created for it instead.
102 lp_alloc(linpool
*m
, uint size
)
104 byte
*a
= (byte
*) BIRD_ALIGN((unsigned long) m
->ptr
, CPU_STRUCT_ALIGN
);
115 if (size
>= m
->threshold
)
117 /* Too large => allocate large chunk */
118 c
= xmalloc(sizeof(struct lp_chunk
) + size
);
119 m
->total_large
+= size
;
120 c
->next
= m
->first_large
;
126 if (m
->current
&& m
->current
->next
)
128 /* Still have free chunks from previous incarnation (before lp_flush()) */
129 c
= m
->current
->next
;
133 /* Need to allocate a new chunk */
135 c
= alloc_page(m
->p
);
137 c
= xmalloc(sizeof(struct lp_chunk
) + m
->chunk_size
);
139 m
->total
+= m
->chunk_size
;
141 c
->size
= m
->chunk_size
;
144 m
->current
->next
= c
;
149 m
->ptr
= c
->data
+ size
;
150 m
->end
= c
->data
+ m
->chunk_size
;
157 * lp_allocu - allocate unaligned memory from a &linpool
158 * @m: linear memory pool
159 * @size: amount of memory
161 * lp_allocu() allocates @size bytes of memory from a &linpool @m
162 * and it returns a pointer to the allocated memory. It doesn't
163 * attempt to align the memory block, giving a very efficient way
164 * how to allocate strings without any space overhead.
167 lp_allocu(linpool
*m
, uint size
)
177 return lp_alloc(m
, size
);
181 * lp_allocz - allocate cleared memory from a &linpool
182 * @m: linear memory pool
183 * @size: amount of memory
185 * This function is identical to lp_alloc() except that it
186 * clears the allocated memory block.
189 lp_allocz(linpool
*m
, uint size
)
191 void *z
= lp_alloc(m
, size
);
198 * lp_flush - flush a linear memory pool
199 * @m: linear memory pool
201 * This function frees the whole contents of the given &linpool @m,
202 * but leaves the pool itself.
209 /* Move ptr to the first chunk and free all large chunks */
210 m
->current
= c
= m
->first
;
211 m
->ptr
= c
? c
->data
: NULL
;
212 m
->end
= c
? c
->data
+ m
->chunk_size
: NULL
;
214 while (c
= m
->first_large
)
216 m
->first_large
= c
->next
;
223 * lp_save - save the state of a linear memory pool
224 * @m: linear memory pool
227 * This function saves the state of a linear memory pool. Saved state can be
228 * used later to restore the pool (to free memory allocated since).
231 lp_save(linpool
*m
, lp_state
*p
)
233 p
->current
= m
->current
;
234 p
->large
= m
->first_large
;
239 * lp_restore - restore the state of a linear memory pool
240 * @m: linear memory pool
243 * This function restores the state of a linear memory pool, freeing all memory
244 * allocated since the state was saved. Note that the function cannot un-free
245 * the memory, therefore the function also invalidates other states that were
246 * saved between (on the same pool).
249 lp_restore(linpool
*m
, lp_state
*p
)
253 /* Move ptr to the saved pos and free all newer large chunks */
254 m
->current
= c
= p
->current
;
256 m
->end
= c
? c
->data
+ m
->chunk_size
: NULL
;
258 while ((c
= m
->first_large
) && (c
!= p
->large
))
260 m
->first_large
= c
->next
;
261 m
->total_large
-= c
->size
;
269 linpool
*m
= (linpool
*) r
;
270 struct lp_chunk
*c
, *d
;
272 for(d
=m
->first
; d
; d
= c
)
280 for(d
=m
->first_large
; d
; d
= c
)
290 linpool
*m
= (linpool
*) r
;
294 for(cnt
=0, c
=m
->first
; c
; c
=c
->next
, cnt
++)
296 for(cntl
=0, c
=m
->first_large
; c
; c
=c
->next
, cntl
++)
298 debug("(chunk=%d threshold=%d count=%d+%d total=%d+%d)\n",
308 lp_memsize(resource
*r
)
310 linpool
*m
= (linpool
*) r
;
314 for(c
=m
->first
; c
; c
=c
->next
)
316 for(c
=m
->first_large
; c
; c
=c
->next
)
319 return (struct resmem
) {
320 .effective
= m
->total
+ m
->total_large
,
321 .overhead
= ALLOC_OVERHEAD
+ sizeof(struct linpool
) +
322 cnt
* (ALLOC_OVERHEAD
+ sizeof(struct lp_chunk
)),
328 lp_lookup(resource
*r
, unsigned long a
)
330 linpool
*m
= (linpool
*) r
;
333 for(c
=m
->first
; c
; c
=c
->next
)
334 if ((unsigned long) c
->data
<= a
&& (unsigned long) c
->data
+ c
->size
> a
)
336 for(c
=m
->first_large
; c
; c
=c
->next
)
337 if ((unsigned long) c
->data
<= a
&& (unsigned long) c
->data
+ c
->size
> a
)