POOL(2)POOL(2)
NAME
poolalloc, poolallocalign, poolfree, poolmsize, poolisoverlap, poolrealloc, poolcompact, poolcheck, poolblockcheck,
pooldump – general memory management routines
SYNOPSIS
#include <u.h>
#include <libc.h>
#include <pool.h>
void* poolalloc(Pool* pool, ulong size)
void* poolallocalign(Pool *pool, ulong size,
ulong align, long offset, ulong span)
void poolfree(Pool* pool, void* ptr)
ulong poolmsize(Pool* pool, void* ptr)
int poolisoverlap(Pool* pool, void* ptr, ulong len)
void* poolrealloc(Pool* pool, void* ptr, ulong size)
int poolcompact(Pool* pool)
void poolcheck(Pool *pool)
void poolblockcheck(Pool *pool, void *ptr)
void pooldump(Pool *pool);
DESCRIPTION
These routines provide a general memory management facility.
Memory is retrieved from a coarser allocator (e.g.
sbrk
or the kernel’s
xalloc)
and then allocated to callers.
The routines are locked and thus may safely be used in
multiprocess programs.
Poolalloc
attempts to allocate a block of size
size;
it returns a pointer to the block when successful and nil otherwise.
The call
poolalloc(0)
returns a non-nil pointer.
Poolfree
returns an allocated block to the pool.
It is an error to free a block more than once or to free a
pointer not returned by
poolalloc.
The call
poolfree(nil)
is legal and is a no-op.
Poolallocalign
attempts to allocate a block of size
size
with the given alignment constraints.
If
align
is non-zero,
the returned pointer is aligned to be equal to
offset
modulo
align.
If
span
is non-zero,
the
n
byte block allocated will not span a
span-byte
boundary.
Poolrealloc
attempts to resize to
nsize
bytes the block associated with
ptr,
which must have been previously returned by
poolalloc
or
poolrealloc.
If the block’s size can be adjusted, a (possibly different) pointer to the new block is returned.
The contents up to the lesser of the old and new sizes are unchanged.
After a successful call to
poolrealloc,
the return value should be used rather than
ptr
to access the block.
If the request cannot be satisfied,
poolrealloc
returns nil, and the old pointer remains valid.
When blocks are allocated, there is often some extra space left at the end
that would usually go unused.
Poolmsize
grows the block to encompass this extra space and returns the new size.
Poolisoverlap
checks if the byte span
[ptr,ptr+len)
overlaps the arenas of the specified
pool,
returning non-zero when there is overlap or zero if none.
The
poolblockcheck
and
poolcheck
routines validate a single allocated block or the entire pool, respectively.
They call
panic
(see below)
if corruption is detected.
Pooldump
prints a summary line for every block in the
pool, using the
print
function (see below).
The
Pool
structure itself provides much of the setup interface.
typedef struct Pool Pool;
struct Pool {
char* name;
uintptr maxsize; /* of entire Pool */
uintptr cursize; /* of Pool */
uintptr curfree; /* total free bytes in Pool */
uintptr curalloc; /* total allocated bytes in Pool */
ulong minarena; /* smallest size of new arena */
ulong quantum; /* allocated blocks should be multiple of */
ulong minblock; /* smallest newly allocated block */
int flags;
int nfree; /* number of calls to free */
int lastcompact; /* nfree at time of last poolcompact */
void* (*alloc)(ulong);
int (*merge)(void*, void*);
void (*move)(void* from, void* to);
void (*lock)(Pool*);
void (*unlock)(Pool*);
void (*print)(Pool*, char*, ...);
void (*panic)(Pool*, char*, ...);
void (*logstack)(Pool*);
void* private;
};
enum { /* flags */
POOL_ANTAGONISM = 1<<0,
POOL_PARANOIA = 1<<1,
POOL_VERBOSITY = 1<<2,
POOL_DEBUGGING = 1<<3,
POOL_LOGGING = 1<<4,
POOL_TOLERANCE = 1<<5,
POOL_NOREUSE = 1<<6,
};
The pool obtains arenas of memory to manage by calling the given
alloc
routine.
The total number of requested bytes will not exceed
maxsize.
Each allocation request will be for at least
minarena
bytes.
When a new arena is allocated, the pool routines try to
merge it with the surrounding arenas, in an attempt to combat fragmentation.
If
merge
is non-nil, it is called with the addresses of two blocks from
alloc
that the pool routines suspect might be adjacent.
If they are not mergeable,
merge
must return zero.
If they are mergeable,
merge
should merge them into one block in its own bookkeeping
and return non-zero.
To ease fragmentation and make
block reuse easier, the sizes requested of the pool routines are rounded up to a multiple of
quantum
before
the carrying out requests.
If, after rounding, the block size is still less than
minblock
bytes,
minblock
will be used as the block size.
Poolcompact
defragments the pool, moving blocks in order to aggregate
the free space.
Each time it moves a block, it notifies the
move
routine that the contents have moved.
At the time that
move
is called, the contents have already moved,
so
from
should never be dereferenced.
If no
move
routine is supplied (i.e. it is nil), then calling
poolcompact
is a no-op.
When the pool routines need to allocate a new arena but cannot,
either because
alloc
has returned nil or because doing so would use more than
maxsize
bytes,
poolcompact
is called once to defragment the memory
and the request is retried.
Pools
are protected by the pool routines calling
lock
(when non-nil)
before modifying the pool, and
calling
unlock
when finished.
When internal corruption is detected,
panic
is called with a
print(2)
style argument that specifies what happened.
It is assumed that
panic
never returns.
When the pool routines wish to convey a message
to the caller (usually because logging is turned on; see below),
print
is called, also with a
print(2)
style argument.
Flags
is a bit vector that tweaks the behavior of the pool routines
in various ways.
Most are useful for debugging in one way or another.
When
POOL_ANTAGONISM
is set,
poolalloc
fills blocks with non-zero garbage before releasing them to the user,
and
poolfree
fills the blocks on receipt.
This tickles both user programs and the innards of the allocator.
Specifically, each 32-bit word of the memory is marked with a pointer value exclusive-or’ed
with a constant.
The pointer value is the pointer to the beginning of the allocated block
and the constant varies in order to distinguish different markings.
Freed blocks use the constant
0xF7000000,
newly allocated blocks
0xF9000000,
and newly created unallocated blocks
0xF1000000.
For example, if
POOL_ANTAGONISM
is set and
poolalloc
returns a block starting at
0x00012345,
each word of the block will contain the value
0xF90012345.
Recognizing these numbers in memory-related crashes can
help diagnose things like double-frees or dangling pointers.
Setting
POOL_PARANOIA
causes the allocator to walk the entire pool whenever locking or unlocking itself,
looking for corruption.
This slows runtime by a few orders of magnitude
when many blocks are in use.
If
POOL_VERBOSITY
is set,
the entire pool structure is printed
(via
print)
each time the pool is locked or unlocked.
POOL_DEBUGGING
enables internal
debugging output,
whose format is unspecified and volatile.
It should not be used by most programs.
When
POOL_LOGGING
is set, a single line is printed via
print
at the beginning and end of each pool call.
If
logstack
is not nil,
it will be called as well.
This provides a mechanism for external programs to search for leaks.
(See
leak(1)
for one such program.)
The pool routines are strict about the amount of space callers use.
If even a single byte is written past the end of the allotted space of a block, they
will notice when that block is next used in a call to
poolrealloc
or
free
(or at the next entry into the allocator, when
POOL_PARANOIA
is set),
and
panic
will be called.
Since forgetting to allocate space for the
terminating NUL on strings is such a common error,
if
POOL_TOLERANCE
is set and a single NUL is found written past the end of a block,
print
will be called with a notification, but
panic
will not be.
When
POOL_NOREUSE
is set,
poolfree
fills the passed block with garbage rather than
return it to the free pool.
SOURCE
/sys/src/libc/port/pool.c
SEE
malloc(2),
brk(2)
/sys/src/libc/port/malloc.c
is a complete example.