]> git.ipfire.org Git - thirdparty/bird.git/blame - lib/resource.c
Lists: Replaced replace_node() by update_node() which is the only use of that function.
[thirdparty/bird.git] / lib / resource.c
CommitLineData
18c8241a
MM
1/*
2 * BIRD Resource Manager
3 *
5cc1e1f8 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
18c8241a
MM
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>
46eb80d5 11#include <stdint.h>
18c8241a
MM
12
13#include "nest/bird.h"
14#include "lib/resource.h"
221135d6 15#include "lib/string.h"
18c8241a 16
5cc1e1f8
MM
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
18c8241a
MM
31struct pool {
32 resource r;
33 list inside;
65d2a88d 34 const char *name;
18c8241a
MM
35};
36
d4bc8dc0
MM
37static void pool_dump(resource *);
38static void pool_free(resource *);
c9763428 39static resource *pool_lookup(resource *, unsigned long);
acb60628 40static size_t pool_memsize(resource *P);
18c8241a
MM
41
42static struct resclass pool_class = {
43 "Pool",
44 sizeof(pool),
45 pool_free,
c9763428 46 pool_dump,
acb60628
OZ
47 pool_lookup,
48 pool_memsize
18c8241a
MM
49};
50
51pool root_pool;
52
53static int indent;
54
5cc1e1f8
MM
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 */
18c8241a 63pool *
65d2a88d 64rp_new(pool *p, const char *name)
18c8241a
MM
65{
66 pool *z = ralloc(p, &pool_class);
5bc512aa 67 z->name = name;
18c8241a
MM
68 init_list(&z->inside);
69 return z;
70}
71
d4bc8dc0 72static void
18c8241a
MM
73pool_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
d4bc8dc0 87static void
18c8241a
MM
88pool_dump(resource *P)
89{
90 pool *p = (pool *) P;
91 resource *r;
92
5bc512aa 93 debug("%s\n", p->name);
18c8241a
MM
94 indent += 3;
95 WALK_LIST(r, p->inside)
96 rdump(r);
97 indent -= 3;
98}
99
acb60628
OZ
100static size_t
101pool_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
c9763428
MM
113static resource *
114pool_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
2cc37815
MM
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
133void 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
5cc1e1f8
MM
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 */
18c8241a
MM
155void
156rfree(void *res)
157{
158 resource *r = res;
159
48e5f32d
OZ
160 if (!r)
161 return;
162
163 if (r->n.next)
164 rem_node(&r->n);
165 r->class->free(r);
665b8e52 166 r->class = NULL;
48e5f32d 167 xfree(r);
18c8241a
MM
168}
169
5cc1e1f8
MM
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 */
18c8241a
MM
179void
180rdump(void *res)
181{
182 char x[16];
183 resource *r = res;
184
083c43e2
OZ
185 bsprintf(x, "%%%ds%%p ", indent);
186 debug(x, "", r);
18c8241a
MM
187 if (r)
188 {
5bc512aa 189 debug("%s ", r->class->name);
18c8241a
MM
190 r->class->dump(r);
191 }
192 else
193 debug("NULL\n");
194}
195
acb60628
OZ
196size_t
197rmemsize(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
5cc1e1f8
MM
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.
daeeb8e9
OZ
214 * Allocated memory is zeroed. Size of the resource structure is taken
215 * from the @size field of the &resclass.
5cc1e1f8 216 */
18c8241a
MM
217void *
218ralloc(pool *p, struct resclass *c)
219{
220 resource *r = xmalloc(c->size);
daeeb8e9 221 bzero(r, c->size);
18c8241a
MM
222
223 r->class = c;
6a8d3f1c
OZ
224 if (p)
225 add_tail(&p->inside, &r->n);
18c8241a
MM
226 return r;
227}
228
5cc1e1f8
MM
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 */
c9763428
MM
240void
241rlookup(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
5cc1e1f8
MM
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 */
18c8241a
MM
259void
260resource_init(void)
261{
262 root_pool.r.class = &pool_class;
ed68a5c6 263 root_pool.name = "Root";
18c8241a
MM
264 init_list(&root_pool.inside);
265}
266
5cc1e1f8
MM
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.
18c8241a
MM
278 */
279
280struct mblock {
281 resource r;
282 unsigned size;
d1abbeac 283 uintptr_t data_align[0];
18c8241a
MM
284 byte data[0];
285};
286
fab37e81 287static void mbl_free(resource *r UNUSED)
18c8241a
MM
288{
289}
290
d4bc8dc0 291static void mbl_debug(resource *r)
18c8241a
MM
292{
293 struct mblock *m = (struct mblock *) r;
294
295 debug("(size=%d)\n", m->size);
296}
297
c9763428
MM
298static resource *
299mbl_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
acb60628
OZ
308static size_t
309mbl_memsize(resource *r)
310{
311 struct mblock *m = (struct mblock *) r;
312 return ALLOC_OVERHEAD + sizeof(struct mblock) + m->size;
313}
314
d4bc8dc0 315static struct resclass mb_class = {
18c8241a
MM
316 "Memory",
317 0,
318 mbl_free,
319 mbl_debug,
acb60628
OZ
320 mbl_lookup,
321 mbl_memsize
18c8241a
MM
322};
323
5cc1e1f8
MM
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 */
18c8241a
MM
337void *
338mb_alloc(pool *p, unsigned size)
339{
340 struct mblock *b = xmalloc(sizeof(struct mblock) + size);
341
342 b->r.class = &mb_class;
3bb10b4d 343 b->r.n = (node) {};
18c8241a
MM
344 add_tail(&p->inside, &b->r.n);
345 b->size = size;
346 return b->data;
347}
348
5cc1e1f8
MM
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 *
cca97066 358 * Please note that mb_allocz() returns a pointer to the memory
5cc1e1f8
MM
359 * chunk, not to the resource, hence you have to free it using
360 * mb_free(), not rfree().
361 */
7a2105be
MM
362void *
363mb_allocz(pool *p, unsigned size)
364{
365 void *x = mb_alloc(p, size);
366 bzero(x, size);
367 return x;
368}
369
3d15dcdb
OZ
370/**
371 * mb_realloc - reallocate a memory block
3d15dcdb
OZ
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;
bf139664
OZ
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.
3d15dcdb
OZ
380 *
381 * Like mb_alloc(), mb_realloc() also returns a pointer to the memory
bf139664 382 * chunk, not to the resource, hence you have to free it using
3d15dcdb
OZ
383 * mb_free(), not rfree().
384 */
385void *
bf139664 386mb_realloc(void *m, unsigned size)
3d15dcdb 387{
665b8e52 388 struct mblock *b = SKIP_BACK(struct mblock, data, m);
3d15dcdb 389
665b8e52 390 b = xrealloc(b, sizeof(struct mblock) + size);
9ac13d7a 391 update_node(&b->r.n);
3d15dcdb
OZ
392 b->size = size;
393 return b->data;
394}
395
396
5cc1e1f8
MM
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 */
18c8241a
MM
403void
404mb_free(void *m)
405{
48e5f32d
OZ
406 if (!m)
407 return;
408
18c8241a
MM
409 struct mblock *b = SKIP_BACK(struct mblock, data, m);
410 rfree(b);
411}
3d15dcdb 412
bf139664
OZ
413
414
415#define STEP_UP(x) ((x) + (x)/2 + 4)
416
417void
418buffer_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
6a8d3f1c 425 *buf = mb_realloc(*buf, nsize * item_size);
bf139664
OZ
426 *size = nsize;
427}