Documented memory resources.
This commit is contained in:
parent
9238b06a2c
commit
5cc1e1f805
5 changed files with 265 additions and 5 deletions
2
lib/Doc
2
lib/Doc
|
@ -2,7 +2,7 @@ H Library functions
|
||||||
S ip.c ipv4.c ipv6.c
|
S ip.c ipv4.c ipv6.c
|
||||||
S lists.c
|
S lists.c
|
||||||
S checksum.c bitops.c patmatch.c printf.c xmalloc.c
|
S checksum.c bitops.c patmatch.c printf.c xmalloc.c
|
||||||
H Resources
|
D resource.sgml
|
||||||
S resource.c
|
S resource.c
|
||||||
S mempool.c
|
S mempool.c
|
||||||
S slab.c
|
S slab.c
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Resource Manager -- Memory Pools
|
* BIRD Resource Manager -- Memory Pools
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: Linear memory pools
|
||||||
|
*
|
||||||
|
* Linear memory pools are collections of memory blocks which
|
||||||
|
* support very fast allocation of new blocks, but are able to free only
|
||||||
|
* the whole collection at once.
|
||||||
|
*
|
||||||
|
* Example: Each configuration is described by a complex system of structures,
|
||||||
|
* linked lists and function trees which are all allocated from a single linear
|
||||||
|
* pool, thus they can be freed at once when the configuration is no longer used.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
|
@ -38,6 +50,15 @@ static struct resclass lp_class = {
|
||||||
lp_lookup
|
lp_lookup
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lp_new - create a new linear memory pool
|
||||||
|
* @p: pool
|
||||||
|
* @blk: block size
|
||||||
|
*
|
||||||
|
* lp_new() creates a new linear memory pool resource inside the pool @p.
|
||||||
|
* The linear pool consists of a list of memory chunks of size at least
|
||||||
|
* @blk.
|
||||||
|
*/
|
||||||
linpool
|
linpool
|
||||||
*lp_new(pool *p, unsigned blk)
|
*lp_new(pool *p, unsigned blk)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +73,20 @@ linpool
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lp_alloc - allocate memory from a &linpool
|
||||||
|
* @m: linear memory pool
|
||||||
|
* @size: amount of memory
|
||||||
|
*
|
||||||
|
* lp_alloc() allocates @size bytes of memory from a &linpool @m
|
||||||
|
* and it returns a pointer to the allocated memory.
|
||||||
|
*
|
||||||
|
* It works by trying to find free space in the last memory chunk
|
||||||
|
* associated with the &linpool and creating a new chunk of the standard
|
||||||
|
* size (as specified during lp_new()) if the free space is too small
|
||||||
|
* to satisfy the allocation. If @size is too large to fit in a standard
|
||||||
|
* size chunk, an "overflow" chunk is created for it instead.
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
lp_alloc(linpool *m, unsigned size)
|
lp_alloc(linpool *m, unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -100,6 +135,16 @@ lp_alloc(linpool *m, unsigned size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lp_allocu - allocate unaligned memory from a &linpool
|
||||||
|
* @m: linear memory pool
|
||||||
|
* @size: amount of memory
|
||||||
|
*
|
||||||
|
* lp_allocu() allocates @size bytes of memory from a &linpool @m
|
||||||
|
* and it returns a pointer to the allocated memory. It doesn't
|
||||||
|
* attempt to align the memory block, giving a very efficient way
|
||||||
|
* how to allocate strings without any space overhead.
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
lp_allocu(linpool *m, unsigned size)
|
lp_allocu(linpool *m, unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -114,6 +159,14 @@ lp_allocu(linpool *m, unsigned size)
|
||||||
return lp_alloc(m, size);
|
return lp_alloc(m, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lp_allocz - allocate cleared memory from a &linpool
|
||||||
|
* @m: linear memory pool
|
||||||
|
* @size: amount of memory
|
||||||
|
*
|
||||||
|
* This function is identical to lp_alloc() except that it
|
||||||
|
* clears the allocated memory block.
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
lp_allocz(linpool *m, unsigned size)
|
lp_allocz(linpool *m, unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -123,6 +176,13 @@ lp_allocz(linpool *m, unsigned size)
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lp_flush - flush a linear memory pool
|
||||||
|
* @m: linear memory pool
|
||||||
|
*
|
||||||
|
* This function frees the whole contents of the given &linpool @m,
|
||||||
|
* but leaves the pool itself.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
lp_flush(linpool *m)
|
lp_flush(linpool *m)
|
||||||
{
|
{
|
||||||
|
|
116
lib/resource.c
116
lib/resource.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Resource Manager
|
* BIRD Resource Manager
|
||||||
*
|
*
|
||||||
* (c) 1998 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -13,6 +13,20 @@
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: Resource pools
|
||||||
|
*
|
||||||
|
* Resource pools (&pool) are just containers holding a list of
|
||||||
|
* other resources. Freeing a pool causes all the listed resources
|
||||||
|
* to be freed as well. Each existing &resource is linked to some pool
|
||||||
|
* except for a root pool which isn't linked anywhere, so all the
|
||||||
|
* resources form a tree structure with internal nodes corresponding
|
||||||
|
* to pools and leaves being the other resources.
|
||||||
|
*
|
||||||
|
* Example: Almost all modules of BIRD have their private pool which
|
||||||
|
* is freed upon shutdown of the module.
|
||||||
|
*/
|
||||||
|
|
||||||
struct pool {
|
struct pool {
|
||||||
resource r;
|
resource r;
|
||||||
list inside;
|
list inside;
|
||||||
|
@ -35,6 +49,14 @@ pool root_pool;
|
||||||
|
|
||||||
static int indent;
|
static int indent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rp_new - create a resource pool
|
||||||
|
* @p: parent pool
|
||||||
|
* @name: pool name (to be included in debugging dumps)
|
||||||
|
*
|
||||||
|
* rp_new() creates a new resource pool inside the specified
|
||||||
|
* parent pool.
|
||||||
|
*/
|
||||||
pool *
|
pool *
|
||||||
rp_new(pool *p, char *name)
|
rp_new(pool *p, char *name)
|
||||||
{
|
{
|
||||||
|
@ -84,6 +106,16 @@ pool_lookup(resource *P, unsigned long a)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rfree - free a resource
|
||||||
|
* @res: resource
|
||||||
|
*
|
||||||
|
* rfree() frees the given resource and all information associated
|
||||||
|
* with it. In case it's a resource pool, it also frees all the objects
|
||||||
|
* living inside the pool.
|
||||||
|
*
|
||||||
|
* It works by calling a class-specific freeing function.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rfree(void *res)
|
rfree(void *res)
|
||||||
{
|
{
|
||||||
|
@ -98,6 +130,15 @@ rfree(void *res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rdump - dump a resource
|
||||||
|
* @res: resource
|
||||||
|
*
|
||||||
|
* This function prints out all available information about the given
|
||||||
|
* resource to the debugging output.
|
||||||
|
*
|
||||||
|
* It works by calling a class-specific dump function.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rdump(void *res)
|
rdump(void *res)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +156,16 @@ rdump(void *res)
|
||||||
debug("NULL\n");
|
debug("NULL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ralloc - create a resource
|
||||||
|
* @p: pool to create the resource in
|
||||||
|
* @c: class of the new resource
|
||||||
|
*
|
||||||
|
* This function is called by the resource classes to create a new
|
||||||
|
* resource of the specified class and link it to the given pool.
|
||||||
|
* Size of the resource structure is taken from the @size field
|
||||||
|
* of the &resclass.
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
ralloc(pool *p, struct resclass *c)
|
ralloc(pool *p, struct resclass *c)
|
||||||
{
|
{
|
||||||
|
@ -125,6 +176,17 @@ ralloc(pool *p, struct resclass *c)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rlookup - look up a memory location
|
||||||
|
* @a: memory address
|
||||||
|
*
|
||||||
|
* This function examines all existing resources to see whether
|
||||||
|
* the address @a is inside any resource. It's used for debugging
|
||||||
|
* purposes only.
|
||||||
|
*
|
||||||
|
* It works by calling a class-specific lookup function for each
|
||||||
|
* resource.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rlookup(unsigned long a)
|
rlookup(unsigned long a)
|
||||||
{
|
{
|
||||||
|
@ -137,6 +199,13 @@ rlookup(unsigned long a)
|
||||||
debug("Not found.\n");
|
debug("Not found.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource_init - initialize the resource manager
|
||||||
|
*
|
||||||
|
* This function is called during BIRD startup. It initializes
|
||||||
|
* all data structures of the resource manager and creates the
|
||||||
|
* root pool.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
resource_init(void)
|
resource_init(void)
|
||||||
{
|
{
|
||||||
|
@ -145,8 +214,17 @@ resource_init(void)
|
||||||
init_list(&root_pool.inside);
|
init_list(&root_pool.inside);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Memory blocks.
|
* DOC: Memory blocks
|
||||||
|
*
|
||||||
|
* Memory blocks are pieces of contiguous allocated memory.
|
||||||
|
* They are a bit non-standard since they are represented not by a pointer
|
||||||
|
* to &resource, but by a void pointer to the start of data of the
|
||||||
|
* memory block. All memory block functions know how to locate the header
|
||||||
|
* given the data pointer.
|
||||||
|
*
|
||||||
|
* Example: All "unique" data structures such as hash tables are allocated
|
||||||
|
* as memory blocks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct mblock {
|
struct mblock {
|
||||||
|
@ -184,6 +262,19 @@ static struct resclass mb_class = {
|
||||||
mbl_lookup
|
mbl_lookup
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mb_alloc - allocate a memory block
|
||||||
|
* @p: pool
|
||||||
|
* @size: size of the block
|
||||||
|
*
|
||||||
|
* mb_alloc() allocates memory of a given size and creates
|
||||||
|
* a memory block resource representing this memory chunk
|
||||||
|
* in the pool @p.
|
||||||
|
*
|
||||||
|
* Please note that mb_alloc() returns a pointer to the memory
|
||||||
|
* chunk, not to the resource, hence you have to free it using
|
||||||
|
* mb_free(), not rfree().
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
mb_alloc(pool *p, unsigned size)
|
mb_alloc(pool *p, unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -195,6 +286,19 @@ mb_alloc(pool *p, unsigned size)
|
||||||
return b->data;
|
return b->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mb_allocz - allocate and clear a memory block
|
||||||
|
* @p: pool
|
||||||
|
* @size: size of the block
|
||||||
|
*
|
||||||
|
* mb_allocz() allocates memory of a given size, initializes it to
|
||||||
|
* zeroes and creates a memory block resource representing this memory
|
||||||
|
* chunk in the pool @p.
|
||||||
|
*
|
||||||
|
* Please note that mb_alloc() returns a pointer to the memory
|
||||||
|
* chunk, not to the resource, hence you have to free it using
|
||||||
|
* mb_free(), not rfree().
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
mb_allocz(pool *p, unsigned size)
|
mb_allocz(pool *p, unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -203,6 +307,12 @@ mb_allocz(pool *p, unsigned size)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mb_free - free a memory block
|
||||||
|
* @m: memory block
|
||||||
|
*
|
||||||
|
* mb_free() frees all memory associated with the block @m.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
mb_free(void *m)
|
mb_free(void *m)
|
||||||
{
|
{
|
||||||
|
|
50
lib/resource.sgml
Normal file
50
lib/resource.sgml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<!--
|
||||||
|
BIRD Programmer's Guide: Resources
|
||||||
|
|
||||||
|
(c) 2000 Martin Mares <mj@ucw.cz>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<chapt>Resources
|
||||||
|
|
||||||
|
<sect>Introduction
|
||||||
|
|
||||||
|
<p>Most large software projects implemented in classical procedural
|
||||||
|
programming languages usually end up with lots of code taking care
|
||||||
|
of resource allocation and deallocation. Bugs in such code are often
|
||||||
|
very difficult to find, because they cause only `resource leakage',
|
||||||
|
that is keeping a lot of memory and other resources which nobody
|
||||||
|
references to.
|
||||||
|
|
||||||
|
<p>We've tried to solve this problem by employing a resource tracking
|
||||||
|
system which keeps track of all the resources allocated by all the
|
||||||
|
modules of BIRD, deallocates everything automatically when a module
|
||||||
|
shuts down and it's is able to print out the list of resources and
|
||||||
|
the corresponding modules they are allocated by.
|
||||||
|
|
||||||
|
<p>Each allocated resource (and from now we'll speak about allocated
|
||||||
|
resources only) is represented by a structure starting with a standard
|
||||||
|
header (struct <struct/resource/) consisting of a list node (resources are
|
||||||
|
often linked to various lists) and a pointer to <struct/resclass/ -- a resource
|
||||||
|
class structure pointing to functions implementing generic resource
|
||||||
|
operations (such as freeing of the resource) for the particular resource
|
||||||
|
type.
|
||||||
|
|
||||||
|
<p>There exist the following types of resources:
|
||||||
|
|
||||||
|
<itemize>
|
||||||
|
<item><it/Resource pools/ (<struct/pool/)
|
||||||
|
<item><it/Memory blocks/
|
||||||
|
<item><it/Linear memory pools/ (<struct/linpool/)
|
||||||
|
<item><it/Slabs/ (<struct/slab/)
|
||||||
|
<item><it/Sockets/ (<struct/socket/)
|
||||||
|
<item><it/Events/ (<struct/event/)
|
||||||
|
<!--
|
||||||
|
are there to keep track of deferred execution.
|
||||||
|
Since BIRD is single-threaded, it requires long lasting tasks to be split to smaller
|
||||||
|
parts, so that no module can monopolize the CPU. To split such a task, just create
|
||||||
|
an <struct/event/ resource, point it to the function you want to have called and call <func/ev_schedule()/
|
||||||
|
to ask the core to run the event when nothing more important will require attention.
|
||||||
|
The actual implementation is system dependent.
|
||||||
|
-->
|
||||||
|
<item><it/Timers/ (<struct/timer/)
|
||||||
|
</itemize>
|
40
lib/slab.c
40
lib/slab.c
|
@ -8,6 +8,23 @@
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: Slabs
|
||||||
|
*
|
||||||
|
* Slabs are collections of memory blocks of a fixed size.
|
||||||
|
* They support very fast allocation and freeing of such blocks, prevent memory
|
||||||
|
* fragmentation and optimize L2 cache usage. Slabs have been invented by Jeff Bonwick
|
||||||
|
* and published in USENIX proceedings as `The Slab Allocator: An Object-Caching Kernel
|
||||||
|
* Memory Allocator'. Our implementation follows this article except that we don't use
|
||||||
|
* constructors and destructors.
|
||||||
|
*
|
||||||
|
* When the |DEBUGGING| switch is turned on, we automatically fill all
|
||||||
|
* newly allocated and freed blocks with a special patterns to make detection
|
||||||
|
* of use of uninitialized or already freed memory easier.
|
||||||
|
*
|
||||||
|
* Example: Nodes of a FIB are allocated from a Slab.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
|
@ -139,6 +156,14 @@ struct sl_alignment { /* Magic structure for testing of alignment */
|
||||||
int x[0];
|
int x[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sl_new - create a new Slab
|
||||||
|
* @p: resource pool
|
||||||
|
* @size: block size
|
||||||
|
*
|
||||||
|
* This function creates a new Slab resource from which
|
||||||
|
* objects of size @size can be allocated.
|
||||||
|
*/
|
||||||
slab *
|
slab *
|
||||||
sl_new(pool *p, unsigned size)
|
sl_new(pool *p, unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -183,6 +208,13 @@ sl_new_head(slab *s)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sl_alloc - allocate an object from Slab
|
||||||
|
* @s: slab
|
||||||
|
*
|
||||||
|
* sl_alloc() allocates space for a single object from the
|
||||||
|
* Slab and returns a pointer to the object.
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
sl_alloc(slab *s)
|
sl_alloc(slab *s)
|
||||||
{
|
{
|
||||||
|
@ -223,6 +255,14 @@ no_partial:
|
||||||
goto okay;
|
goto okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sl_free - return a free object back to a Slab
|
||||||
|
* @s: slab
|
||||||
|
* @oo: object returned by sl_alloc()
|
||||||
|
*
|
||||||
|
* This function frees memory associated with the object @oo
|
||||||
|
* and returns it back to the Slab @s.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
sl_free(slab *s, void *oo)
|
sl_free(slab *s, void *oo)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue