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 poolreset(Pool* pool)
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 multipro-
cess programs.
Poolalloc attempts to allocate a block of size size; it
returns a pointer to the block when successful and nil oth-
erwise. 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
Page 1 Plan 9 (printed 10/24/25)
POOL(2) POOL(2)
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.
Poolreset clears the pool counters and frees all arenas.
The arenas are filled with a pattern before freeing them
when the POOL_ANTAGONISM flag is set. When the free func-
tion of the pool is non-nil, it is called for each arena,
passing its pointer and size.
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 inter-
face.
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 */
Page 2 Plan 9 (printed 10/24/25)
POOL(2) POOL(2)
void* (*alloc)(ulong);
int (*merge)(void*, void*);
void (*move)(void* from, void* to);
void (*free)(void*, ulong);
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 com-
bat fragmentation. If merge is non-nil, it is called with
the addresses of two blocks from alloc that the pool rou-
tines 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 can-
not, either because alloc has returned nil or because doing
so would use more than maxsize bytes, poolcompact is called
Page 3 Plan 9 (printed 10/24/25)
POOL(2) POOL(2)
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 log-
ging 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 allo-
cated 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, freed arenas after
poolreset 0xFF000000. 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 mag-
nitude 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 call-
ers 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
Page 4 Plan 9 (printed 10/24/25)
POOL(2) POOL(2)
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 ALSO
malloc(2), brk(2)
/sys/src/libc/port/malloc.c is a complete example.
Page 5 Plan 9 (printed 10/24/25)