@need 3200

@node Low-level Memory Management
@chapter Low-level Memory Management

The programming interfaces described in this chapter provide
some frequently needed functionality built on top of the standard
functions @code{malloc}, @code{realloc}, and @code{free}.


There are functions that work like @code{malloc} and friends, but
that cause the process to exit with an error message and a 
non-0 status if an allocation fails.  See @ref{Allocate or Die}.


There are functions that let you keep track of how much memory is
used by a particular subsystem of your program, and limit that
amount of memory if you choose. You can use these functions to 
trigger various forms of garbage collection.  See @ref{Allocation With Limitations}.


Finally, There are functions that operate on arrays of bytes.
These do little more than replace standard functions such as
@code{memcpy}, but are included for symmetry and completeness.  See
@ref{Array-of-Byte Functions}.

@menu
* Allocate or Die::
* Allocation With Limitations::
* Array-of-Byte Functions::
@end menu

@need 3200

@node Allocate or Die
@section Allocate or Die
@noindent
@strong{#include <hackerlab/mem/must-malloc.h>}@*
@sp 1

The functions in this section allocate memory.  If an allocation
fails, they call @code{panic} rather than returning.  Thus, these
functions may be used without checking for errors.

@sp 1
@need 1750
@noindent
@b{* Function} @code{must_calloc}@fuindex must_calloc
@*
@example
@group
void * must_calloc (size_t amt);
@end group
@group
@end group
@end example

Return a newly allocated block large enough to hold @code{amt} bytes.
If no such block can be allocated, exit by calling @code{panic}.
Fill the newly allocated memory with @code{0} bytes.

@sp 1
@need 1750
@noindent
@b{* Function} @code{must_malloc}@fuindex must_malloc
@*
@example
@group
void * must_malloc (size_t amt);
@end group
@group
@end group
@end example

Return a newly malloced block large enough to hold @code{amt} bytes.  If
no such block can be allocated, exit by calling @code{panic}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{must_realloc}@fuindex must_realloc
@*
@example
@group
void * must_realloc (void * ptr, size_t amt);
@end group
@group
@end group
@end example

Return a malloced block large enough to hold @code{amt} bytes.  If @code{ptr}
is not @code{0}, it should point to a previously malloced block.  The
contents of the new block are initialized from the contents of
@code{ptr}.  If the new block is not the same as @code{ptr}, @code{ptr} is freed.


If no block can be allocated, exit by calling @code{panic}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{must_free}@fuindex must_free
@*
@example
@group
void must_free (void * ptr);
@end group
@group
@end group
@end example

Free a block allocated by @code{must_calloc}, @code{must_malloc}, or
@code{must_realloc}.




@need 3200

@node Allocation With Limitations
@section Allocation With Limitations
@noindent
@strong{#include <hackerlab/mem/alloc-limits.h>}@*
@sp 1

@geindex allocation limits

@geindex limited allocation



In some situations it is desriable for a subsystem of a program
to limit its use of memory, independently of the rest of the program.
The @code{alloc_limits} functions are for such situations.


There are two steps to using the @code{alloc_limits} functions.  First,
you create an @code{alloc_limits} object which specifies how much memory
your subsystem should, ideally, use, and how much it is permitted to use.
See @strong{make_alloc_limits} in @ref{Specifying Allocation Limits}.  Second, use functions like @code{lim_malloc} 
and @code{lim_free} instead of functions like @code{malloc} and @code{free} in the
subsystem to which the limits apply.

@menu
* Specifying Allocation Limits::
* Allocating and Freeing::
* Reserving Limited Memory::
@end menu

@need 3200

@node Specifying Allocation Limits
@subsection Specifying Allocation Limits

An object of the opaque type @code{alloc_limits} records the rules which
limit memory use in a particular subsystem.

@sp 1
@need 1750
@noindent
@b{* Function} @code{make_alloc_limits}@fuindex make_alloc_limits
@*
@example
@group
alloc_limits make_alloc_limits (t_uchar * name,
                                size_t threshold,
                                size_t failure_pt,
                                int panic_on_failure,
                                lim_free_memory_fn free_memory,
                                void * closure);
@end group
@group
@end group
@end example

Create a new @code{alloc_limits} object.


@code{name} is the name of the subsystem to which these allocation limits
apply.  The name is useful for debugging purposes.


@code{threshold} specifies an ideal limit on the amount of memory used
by your subsystem.  If a subsystem attempts to allocate more than 
@code{threshold} bytes, the @code{free_memory} function for that subsystem
is invoked (see below).  @code{threshold} may be @code{0}, in which case the
@code{free_memory} function is never invoked.


@code{failure_pt} specifies an absolute limit on the amount of memory
used by your subsystem.  Allocations beyond @code{failure_pt} fail
(return @code{0}).


@code{panic_on_failure}, if non-0, means that if the failure point is
reached, or allocation fails, the program will exit with a
message to the standard error stream and a non-0 status.
If @code{0}, allocation failures return @code{0}.


@fuindex lim_free_memory_fn



@code{free_memory} is a function pointer:

@example
@group
     typedef void (*lim_free_memory_fn)(void * closure, 
                                        size_t needed);
@end group
@group
@end group
@end example

It is called immediately before an allocation that would exceed
@code{threshold} (if @code{threshold} is not @code{0}).  @code{closure} is as passed
to @code{make_alloc_limits} (see below).  @code{needed} is the number of 
bytes by which the proposed allocation causes the total amount of
memory used by the subsystem to exceed @code{threshold}.  It is completely
safe to call @code{lim_free} from your @code{free_memory} function.  It
is possible to call @code{lim_malloc} or @code{lim_realloc}, but if your
program does this, @code{free_memory} must be reentrant.


@code{closure} is an opaque value passed to @code{free_memory}.


If a new @code{alloc_limits} object can not be allocated, this function
calls @code{panic} and does not return.


As an alternative to calling @code{make_alloc_limits} in some situations,
three pre-defined allocation limits are declared in @code{alloc-limits.h}:

@example
@group
     extern alloc_limits lim_use_malloc;
     extern alloc_limits lim_use_must_malloc;
     extern alloc_limits lim_no_allocations;
@end group
@group
@end group
@end example

Allocations performed with @code{lim_use_malloc} are unlimited and are
effectively like allocations performed with @code{malloc} or @code{realloc}.
Failed allocations return @code{0}.


Allocations performed with @code{lim_use_must_malloc} are unlimited and
are effectively like allocations performed with @code{must_malloc} or
@code{must_realloc}.  Failed allocations cause the process to exit with
a non-0 status.


Allocations performed with @code{lim_no_allocations} always fail and return
@code{0}.  @code{lim_free} has no effect when passed @code{lim_no_allocations}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{free_alloc_limits}@fuindex free_alloc_limits
@*
@example
@group
void free_alloc_limits (alloc_limits limits);
@end group
@group
@end group
@end example

Free an allocation limits object.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_set_threshold}@fuindex lim_set_threshold
@*
@example
@group
size_t lim_set_threshold (alloc_limits it, size_t threshold);
@end group
@group
@end group
@end example

Modify the @code{threshold} of an @code{alloc_limits} object.  Return
the old @code{threshold}.


This function does not immediately call @code{free_memory}, even if
the total amount of memory allocated exceeds the new @code{threshold}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_threshold}@fuindex lim_threshold
@*
@example
@group
size_t lim_threshold (alloc_limits limits);
@end group
@group
@end group
@end example

Return the current @code{threshold} of allocation limits @code{limits}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_set_failure_pt}@fuindex lim_set_failure_pt
@*
@example
@group
size_t lim_set_failure_pt (alloc_limits limits, size_t failure_pt);
@end group
@group
@end group
@end example

Modify the @code{failure_pt} of an @code{alloc_limits} object.  Return
the old @code{failure_pt}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_failure_pt}@fuindex lim_failure_pt
@*
@example
@group
size_t lim_failure_pt (alloc_limits limits);
@end group
@group
@end group
@end example

Return the @code{failure_pt} of allocation limits @code{limits}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_is_panic_on_failure}@fuindex lim_is_panic_on_failure
@*
@example
@group
int lim_is_panic_on_failure (alloc_limits limits);
@end group
@group
@end group
@end example

Return the value of the @code{panic_on_failure} flag of
allocation limits @code{limits}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_set_panic_on_failure}@fuindex lim_set_panic_on_failure
@*
@example
@group
int lim_set_panic_on_failure (alloc_limits limits, int value);
@end group
@group
@end group
@end example

Set the @code{panic_on_failure} flag of allocation limits @code{limits}.


Return the old value.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_in_use}@fuindex lim_in_use
@*
@example
@group
size_t lim_in_use (alloc_limits limits);
@end group
@group
@end group
@end example

Return the amount (in bytes) of memory allocation charged
to @code{limits} and not yet freed.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_high_water_mark}@fuindex lim_high_water_mark
@*
@example
@group
size_t lim_high_water_mark (alloc_limits limits);
@end group
@group
@end group
@end example

Return the largest amount (in bytes) of outstanding memory 
allocation charged to @code{limits} during the lifetime of the process.




@need 3200

@node Allocating and Freeing
@subsection Allocating and Freeing

These functions allocate and free memory, similarly to 
@code{malloc}, @code{realloc}, and @code{free}, but with allocation limits.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_malloc}@fuindex lim_malloc
@*
@example
@group
void * lim_malloc (alloc_limits limits, size_t amt);
@end group
@group
@end group
@end example

Allocate @code{amt} bytes of memory.


If the allocation would exceed the threshold of @code{limits},
invoke the @code{free_memory} function first.


If the allocation would exceed the @code{failure_pt} of @code{limits}, or if
the underlying @code{malloc} fails, return @code{0} (if the @code{panic_on_failure}
flag of @code{limits} is @code{0}) or exit the process with a non-0 status (if
@code{panic_on_failure} is non-0).


Adjust the @code{in_use} and @code{high_water_mark} of @code{limits}.


If @code{limits} is @code{0}, this function works like @strong{must_malloc} in @ref{Allocate or Die}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_zalloc}@fuindex lim_zalloc
@*
@example
@group
void * lim_zalloc (alloc_limits limits, size_t amt);
@end group
@group
@end group
@end example

Use @code{lim_malloc} to attempt to allocate @code{amt} bytes
of memory.   If allocation succeeds, initialize that
memory to all zero bytes.


Return the allocated region or @code{0} if allocation fails.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_soft_malloc}@fuindex lim_soft_malloc
@*
@example
@group
void * lim_soft_malloc (alloc_limits limits, size_t amt);
@end group
@group
@end group
@end example

Allocate @code{amt} bytes of memory.  Return the newly allocated memory.


If the allocation would exceed the @code{failure_pt} of @code{limits},
or if the underlying @code{malloc} fails, return @code{0} (if the
@code{panic_on_failure} flag of @code{limits} is @code{0}) or exit the
process with a non-0 status.


Adjust the @code{in_use} and @code{high_water_mark} of @code{limits}.


This function @emph{does not} invoke the @code{free_memory} function of
@code{limits}, even if the allocation would exceed the threshold of
@code{limits}.


If @code{limits} is @code{0}, this function works like @strong{must_malloc} in @ref{Allocate or Die}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_realloc}@fuindex lim_realloc
@*
@example
@group
void * lim_realloc (alloc_limits limits, void * prev, size_t amt);
@end group
@group
@end group
@end example

Reallocate @code{prev} as @code{amt} bytes of memory.  Copy (up to) @code{amt} bytes
of data from @code{prev} to the newly allocated memory.


If the allocation would exceed the threshold of @code{limits},
invoke the @code{free_memory} function first.


If the allocation would exceed the @code{failure_pt} of @code{limits},
or if the underlying @code{malloc} fails, return @code{0} (if the
@code{panic_on_failure} flag of @code{limits} is @code{0}) or exit the
process with a non-0 status.


Adjust the @code{in_use} and @code{high_water_mark} of @code{limits}.


If @code{prev} is @code{0}, this function behaves like @code{lim_malloc}.


If @code{limits} is @code{0}, this function works like @strong{must_realloc} in @ref{Allocate or Die}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_soft_realloc}@fuindex lim_soft_realloc
@*
@example
@group
void * lim_soft_realloc (alloc_limits limits,
                         void * prev,
                         size_t amt);
@end group
@group
@end group
@end example

Reallocate @code{prev} as @code{amt} bytes of memory.  Copy (up to) @code{amt} bytes
of data from @code{prev} to the newly allocated memory.


If the allocation would exceed the @code{failure_pt} of @code{limits}, or if
the underlying @code{malloc} fails, return @code{0} (if the
@code{panic_on_failure} flag of @code{limits} is @code{0}) or exit the
process with a non-0 status.


Adjust the @code{in_use} and @code{high_water_mark} of @code{limits}.


This function @emph{does not} invoke the @code{free_memory} function of
@code{limits}, even if the allocation would exceed the threshold of
@code{limits}.


If @code{limits} is @code{0}, this function works like @strong{must_realloc} in @ref{Allocate or Die}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_free}@fuindex lim_free
@*
@example
@group
void lim_free (alloc_limits limits, void * ptr);
@end group
@group
@end group
@end example

Free @code{ptr}.  Adjust the @code{in_use} and @code{high_water_mark} values
of @code{limits}.


If @code{limits} is @code{0}, this function works like @strong{must_free} in @ref{Allocate or Die}.




@need 3200

@node Reserving Limited Memory
@subsection Reserving Limited Memory
@sp 1
@need 1750
@noindent
@b{* Function} @code{lim_prepare}@fuindex lim_prepare
@*
@example
@group
int lim_prepare (alloc_limits limits, size_t amt);
@end group
@group
@end group
@end example

Prepare for an allocation of @code{amt} bytes.


If such an allocation would exceed the threshold of @code{limits},
invoke the @code{free_memory} function first.


If the allocation would exceed the @code{failure_pt} of @code{limits},
return @code{-1}.  Otherwise, return @code{0}.


If @code{limits} is @code{0}, this function simply returns @code{0}.







@need 3200

@node Array-of-Byte Functions
@section Array-of-Byte Functions
@noindent
@strong{#include <hackerlab/mem/mem.h>}@*
@sp 1

These functions operate on regions of memory as arrays of unsigned
bytes with no further interpretation.

@sp 1
@need 1750
@noindent
@b{* Function} @code{mem_set}@fuindex mem_set
@*
@example
@group
void mem_set (t_uchar * mem, unsigned int c, size_t size);
@end group
@group
@end group
@end example

Store @code{size} bytes of value @code{c} beginning at @code{mem}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{mem_set0}@fuindex mem_set0
@*
@example
@group
void mem_set0 (t_uchar * mem, size_t n);
@end group
@group
@end group
@end example

Store @code{n} @code{0} bytes beginning at @code{mem}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{mem_move}@fuindex mem_move
@*
@example
@group
void mem_move (t_uchar * to, const t_uchar * from, size_t amt);
@end group
@group
@end group
@end example

Copy @code{amt} bytes from @code{from} to @code{to}.  The source and destination
regions may overlap.

@sp 1
@need 1750
@noindent
@b{* Function} @code{mem_cmp}@fuindex mem_cmp
@*
@example
@group
int mem_cmp (const t_uchar * m1, const t_uchar * m2, size_t amt);
@end group
@group
@end group
@end example

Compare @code{amt} bytes starting at @code{m1} and @code{m2}.  If a difference is
found, immediately return @code{-1} if the differing byte in @code{m1} is less
than the byte in @code{m2}, @code{1} otherwise.  If no difference is found,
return @code{0}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{mem_occurrences}@fuindex mem_occurrences
@*
@example
@group
size_t mem_occurrences (const t_uchar * mem,
                        unsigned int c,
                        size_t size);
@end group
@group
@end group
@end example

Search @code{size} bytes of data for occurences of byte @code{c} beginning at
@code{mem}.  Return the number of occurences found.







