123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- .TH POOL 2
- .SH NAME
- poolalloc, poolallocalignspan, 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* poolallocalignspan(Pool *pool, ulong size,
- .br
- 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.
|