357 lines
8.4 KiB
Text
357 lines
8.4 KiB
Text
|
.TH POOL 2
|
||
|
.SH NAME
|
||
|
poolalloc, poolallocalign, poolfree, poolmsize, poolrealloc, poolcompact, poolcheck, poolblockcheck,
|
||
|
pooldump \- general memory management routines
|
||
|
.SH SYNOPSIS
|
||
|
.B #include <u.h>
|
||
|
.br
|
||
|
.B #include <libc.h>
|
||
|
.br
|
||
|
.B #include <pool.h>
|
||
|
.PP
|
||
|
.B
|
||
|
void* poolalloc(Pool* pool, ulong size)
|
||
|
.PP
|
||
|
.B
|
||
|
void* poolallocalign(Pool *pool, ulong size,
|
||
|
.br
|
||
|
.B
|
||
|
ulong align, long offset, ulong span)
|
||
|
.PP
|
||
|
.B
|
||
|
void poolfree(Pool* pool, void* ptr)
|
||
|
.PP
|
||
|
.B
|
||
|
ulong poolmsize(Pool* pool, void* ptr)
|
||
|
.PP
|
||
|
.B
|
||
|
void* poolrealloc(Pool* pool, void* ptr, ulong size)
|
||
|
.PP
|
||
|
.B
|
||
|
void poolcompact(Pool* pool)
|
||
|
.PP
|
||
|
.B
|
||
|
void poolcheck(Pool *pool)
|
||
|
.PP
|
||
|
.B
|
||
|
void poolblockcheck(Pool *pool, void *ptr)
|
||
|
.PP
|
||
|
.B
|
||
|
void pooldump(Pool *pool);
|
||
|
.SH DESCRIPTION
|
||
|
These routines provide a general memory management facility.
|
||
|
Memory is retrieved from a coarser allocator (e.g.
|
||
|
.I sbrk
|
||
|
or the kernel's
|
||
|
.IR xalloc )
|
||
|
and then allocated to callers.
|
||
|
The routines are locked and thus may safely be used in
|
||
|
multiprocess programs.
|
||
|
.PP
|
||
|
.I Poolalloc
|
||
|
attempts to allocate a block of size
|
||
|
.BR size ;
|
||
|
it returns a pointer to the block when successful and nil otherwise.
|
||
|
The call
|
||
|
.B "poolalloc(0)
|
||
|
returns a non-nil pointer.
|
||
|
.I 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
|
||
|
.IR poolalloc .
|
||
|
The call
|
||
|
.B "poolfree(nil)
|
||
|
is legal and is a no-op.
|
||
|
.PP
|
||
|
.I Poolallocalign
|
||
|
attempts to allocate a block of size
|
||
|
.B size
|
||
|
with the given alignment constraints.
|
||
|
If
|
||
|
.I align
|
||
|
is non-zero,
|
||
|
the returned pointer is aligned to be equal to
|
||
|
.I offset
|
||
|
modulo
|
||
|
.IR align .
|
||
|
If
|
||
|
.I span
|
||
|
is non-zero,
|
||
|
the
|
||
|
.I n
|
||
|
byte block allocated will not span a
|
||
|
.IR span -byte
|
||
|
boundary.
|
||
|
.PP
|
||
|
.I Poolrealloc
|
||
|
attempts to resize to
|
||
|
.B nsize
|
||
|
bytes the block associated with
|
||
|
.BR ptr ,
|
||
|
which must have been previously returned by
|
||
|
.I poolalloc
|
||
|
or
|
||
|
.IR 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
|
||
|
.IR poolrealloc ,
|
||
|
the return value should be used rather than
|
||
|
.B ptr
|
||
|
to access the block.
|
||
|
If the request cannot be satisfied,
|
||
|
.I poolrealloc
|
||
|
returns nil, and the old pointer remains valid.
|
||
|
.PP
|
||
|
When blocks are allocated, there is often some extra space left at the end
|
||
|
that would usually go unused.
|
||
|
.IR Poolmsize
|
||
|
grows the block to encompass this extra space and returns the new size.
|
||
|
.PP
|
||
|
The
|
||
|
.I poolblockcheck
|
||
|
and
|
||
|
.I poolcheck
|
||
|
routines validate a single allocated block or the entire pool, respectively.
|
||
|
They call
|
||
|
.B panic
|
||
|
(see below)
|
||
|
if corruption is detected.
|
||
|
.I Pooldump
|
||
|
prints a summary line for every block in the
|
||
|
pool, using the
|
||
|
.B print
|
||
|
function (see below).
|
||
|
.PP
|
||
|
The
|
||
|
.B Pool
|
||
|
structure itself provides much of the setup interface.
|
||
|
.IP
|
||
|
.EX
|
||
|
.ta \w'\fL 'u +\w'\fLulong 'u +\w'\fLlastcompact; 'u
|
||
|
typedef struct Pool Pool;
|
||
|
struct Pool {
|
||
|
char* name;
|
||
|
ulong maxsize; /* of entire Pool */
|
||
|
ulong cursize; /* of Pool */
|
||
|
ulong curfree; /* total free bytes in Pool */
|
||
|
ulong 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;
|
||
|
};
|
||
|
.ta \w'\fL 'u +\w'POOL_ANTAGONISM 'u
|
||
|
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,
|
||
|
};
|
||
|
.EE
|
||
|
.PP
|
||
|
The pool obtains arenas of memory to manage by calling the the given
|
||
|
.B alloc
|
||
|
routine.
|
||
|
The total number of requested bytes will not exceed
|
||
|
.BR maxsize .
|
||
|
Each allocation request will be for at least
|
||
|
.B minarena
|
||
|
bytes.
|
||
|
.PP
|
||
|
When a new arena is allocated, the pool routines try to
|
||
|
merge it with the surrounding arenas, in an attempt to combat fragmentation.
|
||
|
If
|
||
|
.B merge
|
||
|
is non-nil, it is called with the addresses of two blocks from
|
||
|
.B alloc
|
||
|
that the pool routines suspect might be adjacent.
|
||
|
If they are not mergeable,
|
||
|
.B merge
|
||
|
must return zero.
|
||
|
If they are mergeable,
|
||
|
.B merge
|
||
|
should merge them into one block in its own bookkeeping
|
||
|
and return non-zero.
|
||
|
.PP
|
||
|
To ease fragmentation and make
|
||
|
block reuse easier, the sizes requested of the pool routines are rounded up to a multiple of
|
||
|
.B quantum
|
||
|
before
|
||
|
the carrying out requests.
|
||
|
If, after rounding, the block size is still less than
|
||
|
.B minblock
|
||
|
bytes,
|
||
|
.B minblock
|
||
|
will be used as the block size.
|
||
|
.PP
|
||
|
.I Poolcompact
|
||
|
defragments the pool, moving blocks in order to aggregate
|
||
|
the free space.
|
||
|
Each time it moves a block, it notifies the
|
||
|
.B move
|
||
|
routine that the contents have moved.
|
||
|
At the time that
|
||
|
.B move
|
||
|
is called, the contents have already moved,
|
||
|
so
|
||
|
.B from
|
||
|
should never be dereferenced.
|
||
|
If no
|
||
|
.B move
|
||
|
routine is supplied (i.e. it is nil), then calling
|
||
|
.I poolcompact
|
||
|
is a no-op.
|
||
|
.PP
|
||
|
When the pool routines need to allocate a new arena but cannot,
|
||
|
either because
|
||
|
.B alloc
|
||
|
has returned nil or because doing so would use more than
|
||
|
.B maxsize
|
||
|
bytes,
|
||
|
.I poolcompact
|
||
|
is called once to defragment the memory
|
||
|
and the request is retried.
|
||
|
.PP
|
||
|
.I Pools
|
||
|
are protected by the pool routines calling
|
||
|
.B lock
|
||
|
(when non-nil)
|
||
|
before modifying the pool, and
|
||
|
calling
|
||
|
.B unlock
|
||
|
when finished.
|
||
|
.PP
|
||
|
When internal corruption is detected,
|
||
|
.B panic
|
||
|
is called with a
|
||
|
.IR print (2)
|
||
|
style argument that specifies what happened.
|
||
|
It is assumed that
|
||
|
.B panic
|
||
|
never returns.
|
||
|
When the pool routines wish to convey a message
|
||
|
to the caller (usually because logging is turned on; see below),
|
||
|
.B print
|
||
|
is called, also with a
|
||
|
.IR print (2)
|
||
|
style argument.
|
||
|
.PP
|
||
|
.B 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
|
||
|
.B POOL_ANTAGONISM
|
||
|
is set,
|
||
|
.I poolalloc
|
||
|
fills blocks with non-zero garbage before releasing them to the user,
|
||
|
and
|
||
|
.I 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
|
||
|
.BR 0xF7000000 ,
|
||
|
newly allocated blocks
|
||
|
.BR 0xF9000000 ,
|
||
|
and newly created unallocated blocks
|
||
|
.BR 0xF1000000 .
|
||
|
For example, if
|
||
|
.B POOL_ANTAGONISM
|
||
|
is set and
|
||
|
.I poolalloc
|
||
|
returns a block starting at
|
||
|
.BR 0x00012345 ,
|
||
|
each word of the block will contain the value
|
||
|
.BR 0xF90012345 .
|
||
|
Recognizing these numbers in memory-related crashes can
|
||
|
help diagnose things like double-frees or dangling pointers.
|
||
|
.PP
|
||
|
Setting
|
||
|
.B 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
|
||
|
.B POOL_VERBOSITY
|
||
|
is set,
|
||
|
the entire pool structure is printed
|
||
|
(via
|
||
|
.BR print )
|
||
|
each time the pool is locked or unlocked.
|
||
|
.B POOL_DEBUGGING
|
||
|
enables internal
|
||
|
debugging output,
|
||
|
whose format is unspecified and volatile.
|
||
|
It should not be used by most programs.
|
||
|
When
|
||
|
.B POOL_LOGGING
|
||
|
is set, a single line is printed via
|
||
|
.B print
|
||
|
at the beginning and end of each pool call.
|
||
|
If
|
||
|
.B logstack
|
||
|
is not nil,
|
||
|
it will be called as well.
|
||
|
This provides a mechanism for external programs to search for leaks.
|
||
|
(See
|
||
|
.IR leak (1)
|
||
|
for one such program.)
|
||
|
.PP
|
||
|
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
|
||
|
.I poolrealloc
|
||
|
or
|
||
|
.I free
|
||
|
(or at the next entry into the allocator, when
|
||
|
.B POOL_PARANOIA
|
||
|
is set),
|
||
|
and
|
||
|
.B panic
|
||
|
will be called.
|
||
|
Since forgetting to allocate space for the
|
||
|
terminating NUL on strings is such a common error,
|
||
|
if
|
||
|
.B POOL_TOLERANCE
|
||
|
is set and a single NUL is found written past the end of a block,
|
||
|
.B print
|
||
|
will be called with a notification, but
|
||
|
.B panic
|
||
|
will not be.
|
||
|
.PP
|
||
|
When
|
||
|
.B POOL_NOREUSE
|
||
|
is set,
|
||
|
.B poolfree
|
||
|
fills the passed block with garbage rather than
|
||
|
return it to the free pool.
|
||
|
.SH SOURCE
|
||
|
.B /sys/src/libc/port/pool.c
|
||
|
.SH SEE ALSO
|
||
|
.IR malloc (2),
|
||
|
.IR brk (2)
|
||
|
.PP
|
||
|
.B /sys/src/libc/port/malloc.c
|
||
|
is a complete example.
|