Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / lib / resource.c @ 6b3f1a54

History | View | Annotate | Download (8.46 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
  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
  add_tail(&p->inside, &b->r.n);
344
  b->size = size;
345
  return b->data;
346
}
347

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

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

    
389
  b = xrealloc(b, sizeof(struct mblock) + size);
390
  replace_node(&b->r.n, &b->r.n);
391
  b->size = size;
392
  return b->data;
393
}
394

    
395

    
396
/**
397
 * mb_free - free a memory block
398
 * @m: memory block
399
 *
400
 * mb_free() frees all memory associated with the block @m.
401
 */
402
void
403
mb_free(void *m)
404
{
405
  if (!m)
406
    return;
407

    
408
  struct mblock *b = SKIP_BACK(struct mblock, data, m);
409
  rfree(b);
410
}
411

    
412

    
413

    
414
#define STEP_UP(x) ((x) + (x)/2 + 4)
415

    
416
void
417
buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_size)
418
{
419
  unsigned nsize = MIN(*size, need);
420

    
421
  while (nsize < need)
422
    nsize = STEP_UP(nsize);
423

    
424
  *buf = mb_realloc(*buf, nsize * item_size);
425
  *size = nsize;
426
}