Statistics
| Branch: | Revision:

iof-bird-daemon / lib / resource.c @ 48e5f32d

History | View | Annotate | Download (8.53 KB)

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
  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, 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
  xfree(r);
167
}
168

    
169
/**
170
 * rdump - dump a resource
171
 * @res: resource
172
 *
173
 * This function prints out all available information about the given
174
 * resource to the debugging output.
175
 *
176
 * It works by calling a class-specific dump function.
177
 */
178
void
179
rdump(void *res)
180
{
181
  char x[16];
182
  resource *r = res;
183

    
184
  bsprintf(x, "%%%ds%%p ", indent);
185
  debug(x, "", r);
186
  if (r)
187
    {
188
      debug("%s ", r->class->name);
189
      r->class->dump(r);
190
    }
191
  else
192
    debug("NULL\n");
193
}
194

    
195
size_t
196
rmemsize(void *res)
197
{
198
  resource *r = res;
199
  if (!r)
200
    return 0;
201
  if (!r->class->memsize)
202
    return r->class->size + ALLOC_OVERHEAD;
203
  return r->class->memsize(r);
204
}
205

    
206
/**
207
 * ralloc - create a resource
208
 * @p: pool to create the resource in
209
 * @c: class of the new resource
210
 *
211
 * This function is called by the resource classes to create a new
212
 * resource of the specified class and link it to the given pool.
213
 * Allocated memory is zeroed. Size of the resource structure is taken
214
 * from the @size field of the &resclass.
215
 */
216
void *
217
ralloc(pool *p, struct resclass *c)
218
{
219
  resource *r = xmalloc(c->size);
220
  bzero(r, c->size);
221

    
222
  r->class = c;
223
  if (p)
224
    add_tail(&p->inside, &r->n);
225
  return r;
226
}
227

    
228
/**
229
 * rlookup - look up a memory location
230
 * @a: memory address
231
 *
232
 * This function examines all existing resources to see whether
233
 * the address @a is inside any resource. It's used for debugging
234
 * purposes only.
235
 *
236
 * It works by calling a class-specific lookup function for each
237
 * resource.
238
 */
239
void
240
rlookup(unsigned long a)
241
{
242
  resource *r;
243

    
244
  debug("Looking up %08lx\n", a);
245
  if (r = pool_lookup(&root_pool.r, a))
246
    rdump(r);
247
  else
248
    debug("Not found.\n");
249
}
250

    
251
/**
252
 * resource_init - initialize the resource manager
253
 *
254
 * This function is called during BIRD startup. It initializes
255
 * all data structures of the resource manager and creates the
256
 * root pool.
257
 */
258
void
259
resource_init(void)
260
{
261
  root_pool.r.class = &pool_class;
262
  root_pool.name = "Root";
263
  init_list(&root_pool.inside);
264
}
265

    
266
/**
267
 * DOC: Memory blocks
268
 *
269
 * Memory blocks are pieces of contiguous allocated memory.
270
 * They are a bit non-standard since they are represented not by a pointer
271
 * to &resource, but by a void pointer to the start of data of the
272
 * memory block. All memory block functions know how to locate the header
273
 * given the data pointer.
274
 *
275
 * Example: All "unique" data structures such as hash tables are allocated
276
 * as memory blocks.
277
 */
278

    
279
struct mblock {
280
  resource r;
281
  unsigned size;
282
  uintptr_t data_align[0];
283
  byte data[0];
284
};
285

    
286
static void mbl_free(resource *r UNUSED)
287
{
288
}
289

    
290
static void mbl_debug(resource *r)
291
{
292
  struct mblock *m = (struct mblock *) r;
293

    
294
  debug("(size=%d)\n", m->size);
295
}
296

    
297
static resource *
298
mbl_lookup(resource *r, unsigned long a)
299
{
300
  struct mblock *m = (struct mblock *) r;
301

    
302
  if ((unsigned long) m->data <= a && (unsigned long) m->data + m->size > a)
303
    return r;
304
  return NULL;
305
}
306

    
307
static size_t
308
mbl_memsize(resource *r)
309
{
310
  struct mblock *m = (struct mblock *) r;
311
  return ALLOC_OVERHEAD + sizeof(struct mblock) + m->size;
312
}
313

    
314
static struct resclass mb_class = {
315
  "Memory",
316
  0,
317
  mbl_free,
318
  mbl_debug,
319
  mbl_lookup,
320
  mbl_memsize
321
};
322

    
323
/**
324
 * mb_alloc - allocate a memory block
325
 * @p: pool
326
 * @size: size of the block
327
 *
328
 * mb_alloc() allocates memory of a given size and creates
329
 * a memory block resource representing this memory chunk
330
 * in the pool @p.
331
 *
332
 * Please note that mb_alloc() returns a pointer to the memory
333
 * chunk, not to the resource, hence you have to free it using
334
 * mb_free(), not rfree().
335
 */
336
void *
337
mb_alloc(pool *p, unsigned size)
338
{
339
  struct mblock *b = xmalloc(sizeof(struct mblock) + size);
340

    
341
  b->r.class = &mb_class;
342
  add_tail(&p->inside, &b->r.n);
343
  b->size = size;
344
  return b->data;
345
}
346

    
347
/**
348
 * mb_allocz - allocate and clear a memory block
349
 * @p: pool
350
 * @size: size of the block
351
 *
352
 * mb_allocz() allocates memory of a given size, initializes it to
353
 * zeroes and creates a memory block resource representing this memory
354
 * chunk in the pool @p.
355
 *
356
 * Please note that mb_allocz() returns a pointer to the memory
357
 * chunk, not to the resource, hence you have to free it using
358
 * mb_free(), not rfree().
359
 */
360
void *
361
mb_allocz(pool *p, unsigned size)
362
{
363
  void *x = mb_alloc(p, size);
364
  bzero(x, size);
365
  return x;
366
}
367

    
368
/**
369
 * mb_realloc - reallocate a memory block
370
 * @m: memory block
371
 * @size: new size of the block
372
 *
373
 * mb_realloc() changes the size of the memory block @m to a given size.
374
 * The contents will be unchanged to the minimum of the old and new sizes;
375
 * newly allocated memory will be uninitialized. Contrary to realloc()
376
 * behavior, @m must be non-NULL, because the resource pool is inherited
377
 * from it.
378
 *
379
 * Like mb_alloc(), mb_realloc() also returns a pointer to the memory
380
 * chunk, not to the resource, hence you have to free it using
381
 * mb_free(), not rfree().
382
 */
383
void *
384
mb_realloc(void *m, unsigned size)
385
{
386
  struct mblock *ob = NULL;
387

    
388
  if (m)
389
    {
390
      ob = SKIP_BACK(struct mblock, data, m);
391
      if (ob->r.n.next)
392
        rem_node(&ob->r.n);
393
    }
394

    
395
  struct mblock *b = xrealloc(ob, sizeof(struct mblock) + size);
396
  replace_node(&b->r.n, &b->r.n);
397
  b->size = size;
398
  return b->data;
399
}
400

    
401

    
402
/**
403
 * mb_free - free a memory block
404
 * @m: memory block
405
 *
406
 * mb_free() frees all memory associated with the block @m.
407
 */
408
void
409
mb_free(void *m)
410
{
411
  if (!m)
412
    return;
413

    
414
  struct mblock *b = SKIP_BACK(struct mblock, data, m);
415
  rfree(b);
416
}
417

    
418

    
419

    
420
#define STEP_UP(x) ((x) + (x)/2 + 4)
421

    
422
void
423
buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_size)
424
{
425
  unsigned nsize = MIN(*size, need);
426

    
427
  while (nsize < need)
428
    nsize = STEP_UP(nsize);
429

    
430
  *buf = mb_realloc(*buf, nsize * item_size);
431
  *size = nsize;
432
}