The alternate memory management routines are used in PAL to provide a way to handle out-of memory conditions.
Available functions:
PalMalloc
: Malloc replacement with out-of-mem handling
PalRealloc
: Realloc replacement with out-of-mem handling
PalCalloc
: Calloc replacement with out-of-mem handling
PalFree
: Free replacement
PalStrdup
: Strdup replacement with out-of-mem handling
SetPalMemFail
: Define your own out-of memory handler
PalMalloc
Allocates memory like malloc does, but will call the
out-of-mem handler when it can't allocate the requested
block. #include "pal.h"
void *PalMalloc(size_t size);size - the amount of memory (in bytes) to allocate.
A pointer to the allocated block of memory. If the
allocation fails, PalMalloc will call the PalMemFail
function with the size of the requested block. The
standard PalMemFail will simply do a FatalExit, but you
can replace it with a more sophisticated one. Please see the introductory chapter of this module for
an explanation of the different possible levels of use
of the PAL memory allocation routines.PalRealloc
Reallocates memory like realloc does, but will call the
out-of-mem handler when it can't allocate the requested
block. #include "pal.h"
void *PalRealloc(void *p, size_t size); p - a pointer to a memory block returned by PalAlloc,
PalRealloc, PalCalloc or PalStrdup.
size - the amount of memory (in bytes) to allocate. A pointer to the new block of memory. If the allocation
fails, PalMalloc will call the PalMemFail function with
the size of the requested block. The standard PalMemFail
will simply do a FatalExit, but you can replace it with a
more sophisticated one. See your C compilers documentation for details on how
realloc works - PalRealloc calls it internally.
Please see the introductory chapter of this module for
an explanation of the different possible levels of use
of the PAL memory allocation routines.PalCalloc
Allocates memory like calloc does, but will call the
out-of-mem handler when it can't allocate the requested
block. #include "pal.h"
void *PalCalloc(size_t n, size_t size); n - the number of elements to allocate
size - the size of one element A pointer to the allocated block of memory. If the
allocation fails, PalCalloc will call the PalMemFail
function with the size of the requested block. The
standard PalMemFail will simply do a FatalExit, but you
can replace it with a more sophisticated one. See your C compilers documentation for details on how
calloc works - PalCalloc calls it internally.
Please see the introductory chapter of this module for
an explanation of the different possible levels of use
of the PAL memory allocation routines.PalFree
Frees a block of allocated memory.
#include "pal.h"
void PalFree(void *p); p - a pointer to a memory block returned by PalAlloc,
PalRealloc, PalCalloc or PalStrdup.None.
See your C compilers documentation for details on how
free works - PalFree calls it internally.
Please see the introductory chapter of this module for
an explanation of the different possible levels of use
of the PAL memory allocation routines. If you use them
at Level 3, you don't need to care about the double
pointer - the 'free' replacement macro does this for
you.PalStrdup
Duplicates a string like strdup does, but will call the
out-of-mem handler when it can't allocate the requested
block. The standard PalMemFail will simply do a FatalExit,
but you can replace it with a more sophisticated one. #include "pal.h"
char *PalStrdup(char *s);s - a pointer to a zero-delimited string.
A copy of the original string.
See your C compilers documentation for details on how
strdup works - PalStrdup calls it internally.
Please see the introductory chapter of this module for
an explanation of the different possible levels of use
of the PAL memory allocation routines.SetPalMemFail
Use this routine to set your own out of memory handler.
Pass it the address of your handler function.
It will return the address of the old handler, in case
you need to set it back.
The handler function itself will get the size of the
block of memory that could not be allocated. It can
itself try to free up sufficient memory. If it thinks
it has been successful in doing so, it should return
TRUE to the caller to trigger another allocation
attempt. Otherwise, it should either do a FatalExit
or return FALSE - in this case, the caller of the
allocation function will get a NULL value return.
Here's what the default PAL out of memory handler looks
like:
int PalMemFail(size_t size)
{
FatalExit("PalMemFail: Out of memory !", 99);
return FALSE; /* not really necessary */
}
As you can see, the default handler does not attempt
to free up memory, it just panicks. #include "pal.h"
void *SetPalMemFail(int (*NewFun)(size_t size)); NewFun - a pointer to your handler. (As a pointer
to a function that accepts a size_t and returns
an int).A pointer to the old handler. (As a void *)
While the standard handler listed above does not return,
your custom version can do so - see the samples below
for further details. void *MyMemFail(size_t size)
{
return FALSE;
}
/* ... */
SetPalMemFail(MyMemFail); /* set new out of mem handler */
/* ... */
This handler is the 'passthru' version. It doesn't do anything -
the behaviour is actually the same as if the whole handler
mechanism wasn't there at all, and the allocation routines would
return themselves, directly.
That's not very useful. This version is more interesting:
int MyMemFail2(size_t size)
{
/* static counter: prevent reentrant calls */
static int CallCount = 0;
int Success;
if(CallCount++) FatalExit("MemFail called recursively !", 1);
/* attempt to free up sufficient memory */
Success = FreeSomeMemory(size);
--CallCount;
if(!Success) FatalExit("Out of memory !", 2);
return TRUE;
}
/* ... */
SetPalMemFail(MyMemFail2); /* set new out of mem handler */
/* ... */
Notice the precaution that is taken against calling the
handler recursively. This can easily happen if you call a
function that itself tries another allocation. MsgBox
would be a good example - since it opens a window and
saves the background of it, it will call PalMalloc
somewhere, and you will end up in your handler again,
recursively. It is recommended that you use this kind of
device in your own handler as well.
Also, be sure to return TRUE IF AND ONLY IF your attempt
to free up some memory succeeded at least partially. If
there was no progress at all, either do a FatalExit or
return FALSE. (If you do the latter, be sure that the
routine that tried to do the allocation handles this
case.) If you return TRUE without having freed any
additional memory, you will end up in an endless loop.