]> git.ipfire.org Git - thirdparty/bird.git/blob - lib/resource.c
Lists: Replaced replace_node() by update_node() which is the only use of that function.
[thirdparty/bird.git] / lib / resource.c
1 /*
2 * BIRD Resource Manager
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 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12
13 #include "nest/bird.h"
14 #include "lib/resource.h"
15 #include "lib/string.h"
16
17 /**
18 * DOC: Resource pools
19 *
20 * Resource pools (&pool) are just containers holding a list of
21 * other resources. Freeing a pool causes all the listed resources
22 * to be freed as well. Each existing &resource is linked to some pool
23 * except for a root pool which isn't linked anywhere, so all the
24 * resources form a tree structure with internal nodes corresponding
25 * to pools and leaves being the other resources.
26 *
27 * Example: Almost all modules of BIRD have their private pool which
28 * is freed upon shutdown of the module.
29 */
30
31 struct pool {
32 resource r;
33 list inside;
34 const char *name;
35 };
36
37 static void pool_dump(resource *);
38 static void pool_free(resource *);
39 static resource *pool_lookup(resource *, unsigned long);
40 static size_t pool_memsize(resource *P);
41
42 static struct resclass pool_class = {
43 "Pool",
44 sizeof(pool),
45 pool_free,
46 pool_dump,
47 pool_lookup,
48 pool_memsize
49 };
50
51 pool root_pool;
52
53 static int indent;
54
55 /**
56 * rp_new - create a resource pool
57 * @p: parent pool
58 * @name: pool name (to be included in debugging dumps)
59 *
60 * rp_new() creates a new resource pool inside the specified
61 * parent pool.
62 */
63 pool *
64 rp_new(pool *p, const char *name)
65 {
66 pool *z = ralloc(p, &pool_class);
67 z->name = name;
68 init_list(&z->inside);
69 return z;
70 }
71
72 static void
73 pool_free(resource *P)
74 {
75 pool *p = (pool *) P;
76 resource *r, *rr;
77
78 r = HEAD(p->inside);
79 while (rr = (resource *) r->n.next)
80 {
81 r->class->free(r);
82 xfree(r);
83 r = rr;
84 }
85 }
86
87 static void
88 pool_dump(resource *P)
89 {
90 pool *p = (pool *) P;
91 resource *r;
92
93 debug("%s\n", p->name);
94 indent += 3;
95 WALK_LIST(r, p->inside)
96 rdump(r);
97 indent -= 3;
98 }
99
100 static size_t
101 pool_memsize(resource *P)
102 {
103 pool *p = (pool *) P;
104 resource *r;
105 size_t sum = sizeof(pool) + ALLOC_OVERHEAD;
106
107 WALK_LIST(r, p->inside)
108 sum += rmemsize(r);
109
110 return sum;
111 }
112
113 static resource *
114 pool_lookup(resource *P, unsigned long a)
115 {
116 pool *p = (pool *) P;
117 resource *r, *q;
118
119 WALK_LIST(r, p->inside)
120 if (r->class->lookup && (q = r->class->lookup(r, a)))
121 return q;
122 return NULL;
123 }
124
125 /**
126 * rmove - move a resource
127 * @res: resource
128 * @p: pool to move the resource to
129 *
130 * rmove() moves a resource from one pool to another.
131 */
132
133 void rmove(void *res, pool *p)
134 {
135 resource *r = res;
136
137 if (r)
138 {
139 if (r->n.next)
140 rem_node(&r->n);
141 add_tail(&p->inside, &r->n);
142 }
143 }
144
145 /**
146 * rfree - free a resource
147 * @res: resource
148 *
149 * rfree() frees the given resource and all information associated
150 * with it. In case it's a resource pool, it also frees all the objects
151 * living inside the pool.
152 *
153 * It works by calling a class-specific freeing function.
154 */
155 void
156 rfree(void *res)
157 {
158 resource *r = res;
159
160 if (!r)
161 return;
162
163 if (r->n.next)
164 rem_node(&r->n);
165 r->class->free(r);
166 r->class = NULL;
167 xfree(r);
168 }
169
170 /**
171 * rdump - dump a resource
172 * @res: resource
173 *
174 * This function prints out all available information about the given
175 * resource to the debugging output.
176 *
177 * It works by calling a class-specific dump function.
178 */
179 void
180 rdump(void *res)
181 {
182 char x[16];
183 resource *r = res;
184
185 bsprintf(x, "%%%ds%%p ", indent);
186 debug(x, "", r);
187 if (r)
188 {
189 debug("%s ", r->class->name);
190 r->class->dump(r);
191 }
192 else
193 debug("NULL\n");
194 }
195
196 size_t
197 rmemsize(void *res)
198 {
199 resource *r = res;
200 if (!r)
201 return 0;
202 if (!r->class->memsize)
203 return r->class->size + ALLOC_OVERHEAD;
204 return r->class->memsize(r);
205 }
206
207 /**
208 * ralloc - create a resource
209 * @p: pool to create the resource in
210 * @c: class of the new resource
211 *
212 * This function is called by the resource classes to create a new
213 * resource of the specified class and link it to the given pool.
214 * Allocated memory is zeroed. Size of the resource structure is taken
215 * from the @size field of the &resclass.
216 */
217 void *
218 ralloc(pool *p, struct resclass *c)
219 {
220 resource *r = xmalloc(c->size);
221 bzero(r, c->size);
222
223 r->class = c;
224 if (p)
225 add_tail(&p->inside, &r->n);
226 return r;
227 }
228
229 /**
230 * rlookup - look up a memory location
231 * @a: memory address
232 *
233 * This function examines all existing resources to see whether
234 * the address @a is inside any resource. It's used for debugging
235 * purposes only.
236 *
237 * It works by calling a class-specific lookup function for each
238 * resource.
239 */
240 void
241 rlookup(unsigned long a)
242 {
243 resource *r;
244
245 debug("Looking up %08lx\n", a);
246 if (r = pool_lookup(&root_pool.r, a))
247 rdump(r);
248 else
249 debug("Not found.\n");
250 }
251
252 /**
253 * resource_init - initialize the resource manager
254 *
255 * This function is called during BIRD startup. It initializes
256 * all data structures of the resource manager and creates the
257 * root pool.
258 */
259 void
260 resource_init(void)
261 {
262 root_pool.r.class = &pool_class;
263 root_pool.name = "Root";
264 init_list(&root_pool.inside);
265 }
266
267 /**
268 * DOC: Memory blocks
269 *
270 * Memory blocks are pieces of contiguous allocated memory.
271 * They are a bit non-standard since they are represented not by a pointer
272 * to &resource, but by a void pointer to the start of data of the
273 * memory block. All memory block functions know how to locate the header
274 * given the data pointer.
275 *
276 * Example: All "unique" data structures such as hash tables are allocated
277 * as memory blocks.
278 */
279
280 struct mblock {
281 resource r;
282 unsigned size;
283 uintptr_t data_align[0];
284 byte data[0];
285 };
286
287 static void mbl_free(resource *r UNUSED)
288 {
289 }
290
291 static void mbl_debug(resource *r)
292 {
293 struct mblock *m = (struct mblock *) r;
294
295 debug("(size=%d)\n", m->size);
296 }
297
298 static resource *
299 mbl_lookup(resource *r, unsigned long a)
300 {
301 struct mblock *m = (struct mblock *) r;
302
303 if ((unsigned long) m->data <= a && (unsigned long) m->data + m->size > a)
304 return r;
305 return NULL;
306 }
307
308 static size_t
309 mbl_memsize(resource *r)
310 {
311 struct mblock *m = (struct mblock *) r;
312 return ALLOC_OVERHEAD + sizeof(struct mblock) + m->size;
313 }
314
315 static struct resclass mb_class = {
316 "Memory",
317 0,
318 mbl_free,
319 mbl_debug,
320 mbl_lookup,
321 mbl_memsize
322 };
323
324 /**
325 * mb_alloc - allocate a memory block
326 * @p: pool
327 * @size: size of the block
328 *
329 * mb_alloc() allocates memory of a given size and creates
330 * a memory block resource representing this memory chunk
331 * in the pool @p.
332 *
333 * Please note that mb_alloc() returns a pointer to the memory
334 * chunk, not to the resource, hence you have to free it using
335 * mb_free(), not rfree().
336 */
337 void *
338 mb_alloc(pool *p, unsigned size)
339 {
340 struct mblock *b = xmalloc(sizeof(struct mblock) + size);
341
342 b->r.class = &mb_class;
343 b->r.n = (node) {};
344 add_tail(&p->inside, &b->r.n);
345 b->size = size;
346 return b->data;
347 }
348
349 /**
350 * mb_allocz - allocate and clear a memory block
351 * @p: pool
352 * @size: size of the block
353 *
354 * mb_allocz() allocates memory of a given size, initializes it to
355 * zeroes and creates a memory block resource representing this memory
356 * chunk in the pool @p.
357 *
358 * Please note that mb_allocz() returns a pointer to the memory
359 * chunk, not to the resource, hence you have to free it using
360 * mb_free(), not rfree().
361 */
362 void *
363 mb_allocz(pool *p, unsigned size)
364 {
365 void *x = mb_alloc(p, size);
366 bzero(x, size);
367 return x;
368 }
369
370 /**
371 * mb_realloc - reallocate a memory block
372 * @m: memory block
373 * @size: new size of the block
374 *
375 * mb_realloc() changes the size of the memory block @m to a given size.
376 * The contents will be unchanged to the minimum of the old and new sizes;
377 * newly allocated memory will be uninitialized. Contrary to realloc()
378 * behavior, @m must be non-NULL, because the resource pool is inherited
379 * from it.
380 *
381 * Like mb_alloc(), mb_realloc() also returns a pointer to the memory
382 * chunk, not to the resource, hence you have to free it using
383 * mb_free(), not rfree().
384 */
385 void *
386 mb_realloc(void *m, unsigned size)
387 {
388 struct mblock *b = SKIP_BACK(struct mblock, data, m);
389
390 b = xrealloc(b, sizeof(struct mblock) + size);
391 update_node(&b->r.n);
392 b->size = size;
393 return b->data;
394 }
395
396
397 /**
398 * mb_free - free a memory block
399 * @m: memory block
400 *
401 * mb_free() frees all memory associated with the block @m.
402 */
403 void
404 mb_free(void *m)
405 {
406 if (!m)
407 return;
408
409 struct mblock *b = SKIP_BACK(struct mblock, data, m);
410 rfree(b);
411 }
412
413
414
415 #define STEP_UP(x) ((x) + (x)/2 + 4)
416
417 void
418 buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_size)
419 {
420 unsigned nsize = MIN(*size, need);
421
422 while (nsize < need)
423 nsize = STEP_UP(nsize);
424
425 *buf = mb_realloc(*buf, nsize * item_size);
426 *size = nsize;
427 }