Daybo Logic's C memory management library V1.0
technical documentation

Contents
1.  About the library
1.1  So who are Daybo Logic?
1.2  Contacting the author
1.3  FAQ

2.0  What are the flavors of the library
2.1  How much does it cost?
2.2  What platforms is the library available for?

3.0  Concepts and structures used by the library
3.1  Getting started
3.2  Portability issues
3.3  8086 builds
3.4  Precompiled headers

4.0  History
4.1  Plans for next version

5.0  Function listings
5.1  Descriptions of all functions and their use



1.  About the library
This could be used as an alternative to
memory tracking tools such as CodeGuard of MemorySleuth,
it's not as thorough as them however, it can't detect memory over
runs on pointer accesses or anything like that.  It can be used
to detect failures to release memory (as long as it's allocated
by us) and attempts to release memory which we do not own.
It has an automatic garbage collection feature to free up all
unfreed memory too.  It should be used by the entire program to
be most effective, it can provide statistics on memory left an
such like too.  The best thing about the MM is that it provides
a central place for dynamic memory allocation in a program so
we can trace all activity, an optional log mode is avialable
though a define.  Swapping is not implemented but may be in a
future version. If the program is going to be released even though
it contains memory bugs, the traps can be turned off or passed to
a handler which will only execute the serious ones.


1.1  So who are Daybo Logic?
Daybo Logic is a commercial software company that at time of writing does not specialize in developing libraries like this for other developers but is actually more of a program making company, established in 1997 we have been making small programs for a long time but now there are more in the team we have to decided to work on some very large products.  Our site on the world wide web is www.daybologic.com


1.2  Contacting the author
The author of this library is David Duncan Ross Palmer, a C/C++ programmer since 1997 and a BASIC programmer since 1989.  Born 5th March 1982 and interested in computers since an early age.  This product was a side effect of wanting to be able trap memory errors on users machines during beta testing phase, it was not originally designed to be released, it was originally too dependant on other Daybo Logic internal libraries.  Mail me: Overlord@DayboLogic.co.uk


1.3  FAQ - Frequently Asked Questions and common compile problems

Q - Error DPCRTLMM.H 53: Declaration missing ;
A - This stumped me for a while too, this can only happen if you have the source and selected to have explict far data for the 16-bit tiny, small or medium memory models.  The answer is one of these solutions I hope, firstly check the language is set to non-ANSI compliance, if your compiler only supports ANSI you cannot support explicit far pointers so give up!  The other problem is on line 112 (ish) of BUILD.H #define DPCRTLMM_FARDATA _ _ far, change the _ _ far bit to just far and try again.  Look for what the 'far' keyword equivilant is in your language.  If you still have problems contact me.

Q - No prototype for function 'farmalloc' or 'farcalloc' or 'farfree' or 'farrealloc'
A - The explicit fars are non-ANSI, unfortunately the functions differ from one compiler to the next when one strays from ANSI.  In BUILD.H there are a list of functions here, change them to point to your compiler's equivilant functions if you can discover what they are.  If you don't have any you will have to give up and turn off this option, make sure you don't have strict ANSI C compliance on or anything first but if all else fails just compile for the compact/large or huge model.

Q - I want to compile for 16-bit x86 processors in small memory models
A - The library only functions correctly with far data, edit BUILD.H and define the macro DPCRTLMM_WANTFARDATA

Q - My program is crashing unexpectedly when I try to free blocks of memory (or earlier while using the memory manager)
A - The most common problem is forgetting to start the library, if this is not the case and you are compiling for a 16-bit processor it may be that the data is near.  The easiest way to avoid this is to rebuild in a memory model which has far data.  There is another way in this version of the library, open BUILD.H and find the commented out macro called DPCRTLMM_WANTFARDATA and remove the comments.  If this does not solve the problem please send me all details possible.



2.0  What are the flavors of the library?
The library is only written for C applications and comes in three different flavors, the one you have depends how much you payed for it.

Standard version - The standard version is the version which most people will probally have, it is freeware and has limited functionallity.  It comes with builds for DOS and Win32 and the header to use the library.  The version offers all the functionallity excluding what is offered in the others.

Professional version - Adds advanced debug hook support for tracing calls for allocations / deallocations etc. so that the programmer's own code can view this information before allowing it to be passed on to another hook, or stopping it.

Absolutely mental version - Everything mentioned above plus laerger size hook chains and double sized maximum safety list.  All source and debug builds supplied so these items could be modified even further, far past madness, it's mental.



2.1  How much does it cost?
The standard version of the library costs nothing and does not expire, anyone may download this from Daybo Logic's site and use it.  The professional version costs £10 and will always be updated free of charge.  The absolutely mental version costs £20 but it's worth it because it can be built for any platform anywhere, it's all written in ANSI C, if any problems happen, support is provided free of charge.


2.2  What platforms is the library available for
The standard and professional versions of the library are generally built for 16-bit DOS, some of the memory models using Turbo C++ 3 and there is a Win32 386/Pentium build which is flat, these are built with Borland C++ 5.02, I will build it for Linux or FreeBSD if there is enough domand.  I will build a version for Micro$oft Visual C++ 6.0 in due course.  The absolutely mental version comes with source and because it complies to ANSI C (1990) is may be built for any platform.


3.0  Concepts and structures used by the library
The primary memory managment structure is called a block descriptor, it contains basic information about a block of memory allocated by the program, it is not normally directly accessed by a program, it is generally only used by the library, it is possible to access it but I don't know why a program would need to because all information may be obtained using the library interface.

These block descriptors contain this simple information: The block's base address, size in bytes and a number of flags with special meanings.

The other structure you will encounter is the block descriptor array.  I recommend that every C file maintains it's own array.  When a block is allocated it's decriptor is always inserted into one of these arrays and nearly every library call will want to know the address of one of these arrays.  This only causes a problem if the program  passes a descriptor to another module the program which tries to get size information on the block using the library functions while passing it's own array, then the program will be terminated because the library will assume that the address is invalid.  I recommend using NULL as a placeholder for arrays, for blocks which are designed to be shared.  Normal sharing is fine, as long as the library is not used on that block from another module.

The final structure is stored internally and the program should never need to access, this structure is called the safety list.  It is a large fixed size array of all the addresses of the block descriptor arrays used throughout the program.  The interface to this list is kept internal to the library, if you want to access it you could always add it to DPCRTLMM.H if you have the source code although there should be no reason to do this.

The only time you will encounter the safety list is if you run out of space.  By default the standard library comes with 64 entries which is about normal for most programs.  The professional version comes with 512 entries which is massive.  Purchasing the source code will man you may change the size to anything and / or expose the hidden interface to the safety list.

So what is this safety list for if I can't access it under normal circumstances?  Well it's used to trap any call to the library which specifies an invalid pointer to a block descriptor array.  It is also processed when the library is shut down to ensure all blocks have been released, it is therefore is the primary structure for producing a leak report.



3.1  Getting started
If you already have a program to convert to use the library I suggest this.  Make yourself a set of dummy wrappers called mm_alloc()  mm_free() etc.  Then add some defines to make alloc call them.  In the wrappers module create on global block descriptor array and then add to it using the library when the functions get called.  This is the most portable approach because the main part of the program does not know it is using the library, however all special features such as getting the size of a block of memory locking blocks of memory and having multiple arrays of blocks will be lost.

If you are writing a new program use the library from the start, add a block descriptor array structure to the main module at file level, then in main call the library startup routine, create the array then allocate blocks using it.  When main() is about to exit free all blocks, destroy the array with the dedicated function and shutdown the library.  These destroy and shutdown routines are the main ones which check if anything was not freed from the array etc.

I have supplied an example with the library to help you see this in action, it is called example.c, actually as you will see, it intentionally fails to free hald of the blocks.



3.2  Portablilty issues
This library will slow the program down but not make it any less portable as such.  However if you later want to speed the program up and remove the library read the section Getting Started, the first paragraph describes a hack, designing the program in the first place to use this hack is the only way to easily remove the library.  Another approach might me to write a dummy version of the library, only doing the bare minimum, I may write one of these when I have nothing to do.

By default the library source is portable, it can be setup to use some non-ANSI features:
far pointers and precompiled headers.  Most instructions for changes are in build.h, however allowing PCH pragmas has to be done with a predefinition.  See section 3.4



3.3  8086 builds
When building the library for the 8086-80286 (16-bit versions of Intel's processor) the library should be built for one of these memory models: Compact, Large or Huge.  Trying to build the library for smaller memory models results in near data.  If such a build is made I have discovered that the hosting program will be assuming the wrong data segment when the pointers are returned from the library.  There is a way to get around this if you really want to use a smaller memory model, modify the source so that all the pointers are far, this is non-ANSI but can easily be acheived, there are instructions in BUILD.H.


3.4  Precompiled headers
My compiler (Borland C++) supports this pragma:
#pragma hdrstop
However using it on other compilers might cause a warning, to avoid annoyance to people I have removed all these by default, to get them back define DPCRTLMM_HDRSTOP.  Note: This must be a predefine, defining it in build.h will be ineffective, since build.h is processed after the position where I want to add the #pragma.


4.0  History
2nd May 2000 - Overlord:
Removed dependancies that made this library rely on other Daybo Logic
libraries, this will mean the library can be used by Colelus without
disrupting the portability of the Colelus source tree.  This step
involves stripping out all references to STDS\DLSTRLIB.H a very annoying
thing to do because all code which is Daybo Logic shared code (and therefore
not part of Colelus) should include this header.  However if this library
source is to be made available to the public too, this dependancy must go.
The other dependacy which follows in a similar fasion is the use of the
generic list object as the list of block arrays, the so-called safety list.
To avoid this I will design a safety list object type which is only used by
us and indeed only makes sense to us!  This new object definition is in
SAFELIST.H and the code to run is SAFELIST.C

3rd May 2000 - Overlord:
Totally got rid of SAFELIST.C/.H and decided to start again.  The
declaration of the safety list object is in INTDATA.C and the size is
determined in the configuration file BUILD.H
The new SAFELIST.C will contain simple functions to save having to write
the list processing several times, code to count the number of items,
code to add a new one at the first blank entry and remove items.
There is no need for a linked list or shift up code because it's a fixed
size determined at compile time therefore anything which is not a valid
entry will just be NULL.

4th May 2000 - Overlord:
Compiled in the new SAFELIST.C and tried to build the library muliple times
until all references to other Daybo Logic stuff were stripped out.  BOOL had
to change to unsigned int, however the user of the library may still treat
these values as BOOL/TRUE/FALSE even though they are used as unsigned ints
inside the library.  The user can only do this if they have their own
compatible versions of BOOL/TRUE/FALSE which most developers have by now, or
can easily make them if they do now have them.
Also changed defintion of _safeList and all people who used it had to be
altered to be aware of the new definition.
Wrote a new page on the web site offering it for sale.

5h May 2000 - Overlord:
Wrote documentation for library and released it on the Daybo Logic web site
http://www.daybologic.co.uk

10th May 2000 - Overlord:
There was a bug in the new safety list which stopped the whole library
working, a single missing '!' (logical not).  Republishing the library.

14th June 2000 - Overlord:
In 16-bit memory models on x86 processors, if the data segment is near the pointers do not mean anything to the hosting program when given to it, the near pointers are for us with DPCRTLMM's own assumed data segment, therefore explicit far data is needed, added a macro to build.h for doing so and severely modified this documentation.

18th July 2000 - Overlord:
OK this isn't a technical note, it's just that today I set myself the deadline of August 1st for the version 1.0 release.

19th July 2000 - Overlord:
Coverted all the filenames to lower case and all the #includes to lower case for compatibility with UNIX systems.
Tried and failed miserably to create a working makefile and the Borland C++ IDE auto-generated one came up with warnings about some of my symbols not being in the library, works ok from the IDE and I don't ever get warnings for it so I gave up on this for now.  The library is saimple enough to build I feel.
    Merged BBATRAP and BBPTRAP, well, put them in the same module with another function call _VerifyPtrs() which calls both, this stops having to do both calls in some functions which looks untidy.  Both functions were always called at once anyway, the new module is called vptrap.c
    In realloc.c the string "Realloc()" was used twice, optimized out second instance.
    Noticed quite a few modules called the old BBA trap and did not have a pointer to verify also, so I changed _VerifyPtrs() slightly so argument three could be NULL and the second trap call would be skipped.  Well mustn't grumble, it still feels cleaner this way and I got rid of a whole module in effect!
Free() used the string "Free()" twice, made it share a variable, only has an effect on non-optimizing compilers which don't support duplicate strings merged.
    Removed all #pragma hdrstop PCH support unless DPCRTLMM_HDRSTOP is defined, to save annoying warnings to people who's compiler does not understand the pragma
  Added support for NULL as the default built-in block array, define DPCRTLMM_NONULL_BLOCKDESCARRAY in build.h to restore old behaviour, old behaviour was to say that NULL was not a valid block desc array and crash the program.
    Added a hack table for shorter function names, this was suggested by Jeremy and will also shorten the structure names.  Developers already using the library can totally ignore this.

20th July 2000 - Overlord:
In adding the support for default block arrays I had to split up the trap routine called TrapUnFreedArrays() in strtstop.c into a new routine also TrapUnFreedBlocks().  I realized that not all data which is unfreed (garbage) is just arrays now due to the default array which is never destroyed but can contain blocks.  I renamed the define DPCRTLMM_TRAP_UNFREED_ARRAYS to DPCRTLMM_TRAP_UNFREED_DATA.  If you used this (which I doubt) at this stage just rename the macro in your code.

21st July 2000 - Overlord:
Corrected an assertion failure due to the new NULL block array.  In the betas, when DPCRTLMM_LOG was not defined the messages were not output to a log file but the messages were still taking space in the resulting program, got rid of most of them, some are used as traps too so I couldn't get rid of them.  To try to stop users making the mistake of including build.h in their own programs I made build.h look for a macro I define in my source only.
    Loads of warnings about variables that were never used when I tried to define DPCRTLMM_LOG for an experiment, filtered them all out, all the #ifdef DPCRTLMM_LOG #endif /*DPCRTLMM_LOG*/ stuff everywhere looks a right mess though.

24th July 2000 - Overlord:
Limited block descriptor arrays to 64 entries in standard builds

26th July 2000 - Overlord:
Added a new module getstats.c, countains these functions: dpcrtlmm_GetBlockCount( ) & dpcrtlmm_GetStats( ), GetStats( ) is very simple and it uses _blockCount which I added to intdata.c. Alloc()/Free() don't update the counter yet
Limited library to 50 blocks for standard builds, first set up a define in build.h so I could modify it easily and then put all the statistics (except flag counting) into internal vars (intdata.c).  Flag counting is done by an internal routine called CountFlagsInUse( ), I put that in getstats.c
    Added dpcrtlmm_AreTrapsEnabled( )
    There is now an extern in town called dpcrtlmm__EnableTraps, it used to be an internal variable called dpcrtlmm_int__enableTraps, now the modifiers dpcrtlmm_EnableTraps( ), dpcrtlmm_DisableTraps( ) & dpcrtlmm_AreTrapsEnabled( ) are just macros to use it.
    Making this new extern meant the simple module enbltrap.c was redundant, deleted it.
    Limited standard version of the library to 50 blocks, not sure it's turned off in payed for versions, better test that or I could be in trouble!

27th July 2000 - Overlord:
Been doing other stuff mainly, we ran out of coffee, arghhh!  Fixed a link problem and Mike agreed to test the library.
Got Alloc()/Free() to update statistics, got code to work to nag user and terminate the program if more than DPCRTLMM_STDBLOCKLIMIT blocks are used in the program, oh and no worries it doesn't nag registered users.

28th July 2000 - Overlord:
Renamed getstats.c stats.c, added support for the default array into CountFlagsInUse( ).  It seems Alloc( ) is correctly allocating blocks in the default array because of the NULL array resolver macro, must be Free( ) that is not so aware.  I have noticed that GrowBlockArray( ) is relying on the run-time library realloc( ) to accept NULL and pass it on to alloc( ), I'm not sure that this is always supported, I may have to change it.  Had to make some changes to isbad.c both IsBad...( ) calls did not resolve array pointers and dpclrtmm_IsBadArrayPtr( ) was so somple it was just asking the safety list.  Some functions may try dereferencing NULL pointers without resolving them first so I'll have to find all this instances of this behaviour, all functions which are exposed in the library so the user can call them will probally be affected.
    Whoops!  vptrap.c is a bit odd, looking for bad blocks is simple, it called IsBadBlockPtr( ), seems logical, and yet the trap on a bad array pointer (the trap above) decides to call the safety list itself, hmm, it might be more advisable to call IsBadArrayPtr( ) of course, changing code again....

29th July 2000 - Overlord:
The trap unfreed arrays routine was always seeing one less block then it should, traced the problem down to a loop which looked at PArr->Count but that count was being changed by dpcrtlmm_Free( ) which the routine was calling as automatic garbage collection on every unreleased block it found.  I changed it to while ( PArr->Count ) and took off element 0

30th July 2000 - Overlord:
The change to the loop has (or perhaps not but I suspect it's this) has caused the machine to halt running as a 16-bit program under DOS.  I have been trying to debug it all day but it's very hard to see what goes wrong, might have to re-write this loop in the next release, it's too close to release day now, I'll have to say that the library is currently limited to flat builds ie. 32-bit.
Wrote dpcrtlmm_Ver( ), which uses DPCRTLMM_VER as in build.h

31st July 2000 - Overlord:
Hmm, this morning the program no longer halts, if anybody out there decides to read this revision history I'd really like to know what was going on!  Not a lot of programming done today, too hot.  Only 7 hours until it's midnight in the USA so I should have the demos built by then.

1st August 2000 - Overlord:
Altered the way the version number is reported, it now puts data into a small structure, S_DPCRTLMM_VERSION, removed the define from build.h and made the structure in dpcrtlmm.h  I don't think the debug hooks are properly set up I noticed dpcrtlmm_CreateBlockArray( ) at no time lead to the hook chain being processed.  Must fix this in all functions I suspect.
    Added dpcrtlmm_IsDefaultBlockArray( )
    Whoops saw dpcrtlmm_Realloc( ) forgot to resolve NULL arrays, fixed.
Invalid page faults were being caused at the end, changed raise(SIGABRT) to abort( ), then found this wasn't the real cause, the real cause was the library was designed for the static run time library and then example was built for the DLL version.  I'll leave that as abort( ) anyway.



4.1  Plans for next version
The internal debug hook executive seems to use a parameter which it could get from the debug info structure passed to it, the hook type is not used and is a waste.  This does not effect callers of the library, since the debug hook executive cannot be called from outside.

Swapping to disk should be implemented with an LRU algortihm, based on the flag in block descriptor (unswappable, bit 1) and the block descriptor may have to be extended with more fields to support this.

The library is a bit slow due to an excessive amount of calls to _VerifyPtrs( ), which an internal routine called to check the user's pointers are valid, however it's also called when functions call other functions, even though they already know the pointers are safe, to avoid this I may make an inner shell, where the user calls safety wrappers around the real library and all functions call the inner shell functions and not the entrypoints the users sees.



5.0 Function listings
No documentation is supplied or can be found that I have written for the hidden functions which I believe it is not worth library users trying to access.  The file DPCRTLMM.H contains most structures that will be of any interest too.  If you have the library source you can read all the other headers to discover the hidden interface if you are that nosey.

dpcrtlmm_InstallDebugHook( )
dpcrtlmm_GetDebugHookChainCount( )
dpcrtlmm_GetDebugHookMatrixCount( )
dpcrtlmm_UninstallDebugHook( )
dpcrtlmm_Alloc( )
dpcrtlmm_Free( )
dpcrtlmm_CreateBlockArray( )
dpcrtlmm_DestroyBlockArray( )
dpcrtlmm_IsDefaultBlockArray( )
dpcrtlmm_Startup( )
dpcrtlmm_Shutdown( )
dpcrtlmm_GetBlockSize( )
dpcrtlmm_IsBadBlockPtr( )
dpcrtlmm_IsBadArrayPtr( )
dpcrtlmm_Realloc( )
dpcrtlmm_Calloc( )
dpcrtlmm_InstallTrapCallback( )
dpcrtlmm_RemoveTrapCallback( )
dpcrtlmm_GetTrapCallbackInfo( )
dpcrtlmm_ModifyDescriptorFlags( )
dpcrtlmm_SetBlockLockingFlag( )
dpcrtlmm_IsBlockLocked( )
dpcrtlmm_LockBlock( ) & dpcrtlmm_UnlockBlock( )
dpcrtlmm_ToggleBlockLockingStatus( )
dpcrtlmm_EnableTraps( )
dpcrtlmm_DisableTraps( )
dpcrtlmm_AreTrapsEnabled( )
dpcrtlmm_GetStats( )
dpcrtlmm_GetBlockCount( )
dpcrtlmm_Ver( )

External variables
dpcrtlmm__EnableTraps



5.1  Descriptions of all functions and their use

unsigned int dpcrtlmm_InstallDebugHook(const unsigned short HookType, unsigned int(*NewHookProc)(PS_DPCRTLMM_DEBUGHOOKINFO));
Installs a new debug hook into the internal debug hook chain, read DPCRTLMM.H for a complete list of hook types.  The debug hook handler will accept a pointer to a structure full of information which will be of use for debugging, some of this information will be debug hook type dependant.  If the hook is installed correctly the function returns 1 (true), if the hook is of bad type or cannot be installed the return value is 0 (false).  Your user defined hook routine should take one of these actions, return 0U if you do not wish for other hooks which follow you in the chain to be notified and called also, return 1U if I may call following hooks.

unsigned dpcrtlmm_GetDebugHookChainCount(const unsigned int HookType);
Returns the number of hooks installed for this hook type, it is not valid to use DPCRTLMM_HOOK_ALL for this functionalliy use dpcrtlmm_GetDebugHookMatrixCount( )

unsigned dpcrtlmm_GetDebugHookMatrixCount(void);
Counts the number of hooks in the entire debug hook matrix, that is the total number of hooks for all types, it is very unlikely that a program will have a practical use for this, I just thought I'd add it really, plus it has a cool name!

unsigned int dpcrtlmm_UninstallDebugHook(const unsigned short HookType, unsigned int(*HookProc2Remove)(PS_DPCRTLMM_DEBUGHOOKINFO));
Remove the said hook, type of hook should be specified in order to find it, although the same hook handler can be installed for many hooks, so DPCRTLMM_HOOK_ALL is allowed.
It's not allowed to uninstall hooks by index, the address of the hook handler must be specified.  On success 1 (true) is returned otherwise 0 (false) is returned.

void* dpcrtlmm_Alloc(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const size_t NewBlockSize);
This function is the main allocation function, the equivillant to malloc( ) in the C Run time library.  It's prototype seems more complex only because of the block descriptor array.  Block descriptor arrays are for organization purposes, use dpcrtlmm_CreateBlockArray( ) to get one before allocating any blocks of memory or specify NULL to use the define array provided by DPCRTLMM.  The size in bytes of the desired block should be specified.  NULL is returned if the block cannot be allocated, check the log to make sure this is what caused the error, any non-zero return is a pointer to the newly allocated block of memory.  Debug hooks installed and watching activities with this event will not see allocation requests unless they are valid, I'll fix this by the next version.

void dpcrtlmm_Free(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, void* Ptr);
This function is the main deallocation function, the equivilant to free( ) in the C Run time library.  The block descriptor array in which the block was allocated must be specified, even if it is NULL, which represents the default internal library array, if the block did not belong to the array you specify a trap will be executed.  If a debug hook is installed on this type of event, remember that it must never dereference the PRelDesc field, the descriptor will have already been released.

PS_DPCRTLMM_BLOCKDESCARRAY dpcrtlmm_CreateBlockArray(void);
Creates a new block descriptor array.  A block descriptor array is returned and should be kept.  Then during allocations one can use the returned pointer in the first parameter.  Don't forget to free all blocks from an array and destroy it with dpcrtlmm_DestroyBlockArray( ) before the returned pointer goes out of scope.  I recommend each module, or each major section of a large project has it's own block descriptor array.  I also recommend that the main module of the program and any shared memory should use the "NULL" block array, when dpcrtlmm_Alloc( ) asks for a pointer to a block array just supply NULL to use it.  Hooking this event is allowed, hooks will be executed whether this function succeeds or fails, check the Success indicator of the debug hook info your hook is passed.

void dpcrtlmm_DestroyBlockArray( PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray );
Destroys the said block descriptor array.  NULL is not allowed, the reason is NULL for a block descriptor array represents an internal default array which the user is not allowed to destroy.  If the pointer supplied is not in the internal safety list as a valid block array allocated by dpcrtlmm_CreateBlockArray( ), a trap will be executed.  There is no return value.  Hooks will normally see both success and failure, check the Success entry of the debug hook info.

unsigned int dpcrtlmm_IsDefaultBlockArray( PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray );
In debug hooks and the like, the user may be returned a pointer which does not corrospond to any of the pointers which were allocated, in this case it may be the resolved NULL pointer to the default array because the array is not directly available for comparison use this function to determine if that is the case, it will also report 1U (TRUE) for NULL since this is the unresolved user version.  Hooking this function is not supported, if you want it, call me.

void dpcrtlmm_Startup(void);
Before one calls any other functions in this library, the library must be started, this allows various initialization tasks, there are currently no tests applied to ensure the library is started before any other functions are called, it's too time consuming as every function would have to call the test, the behaviour of the program calling the library before it is started is undefined and could end in disaster.

void dpcrtlmm_Shutdown(void);
If one ends the program without shutting down the library the whole point of this library becomes hidden, calling this function does not just allow internal library cleanup but will activate the search for unfreed memory and is the point at which all the leaks will be revealed.  I can't make sure the program writer calls this unfortunately, I would recommend setting it up with atexit( ) as soon as the program to starts just incase the program ends from somewhere other than main( ).  Personally I keep a routine called GlobalShutdown( ) or whatever in the main module of my programs which lists all global libraries to shutdown and global memory to cleanup etc. and then just register that one function with atexit( ), thus overcoming the 32 entry limit in atext( ).  Also my programs contain GlobalStartup( ) which, as it's first function installs GlobalShutdown( ) with atext( ) and then inits all the libraries, I then call GlobalStartup( ) as the first thing to do in main( ) and then I don't have to worry about it.

size_t dpcrtlmm_GetBlockSize( PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, void* BlockPtr);
Returns the size of a block which one allocated earlier.  The address of the allocated block must be specified also.  The size will be returned.

unsigned int dpcrtlmm_IsBadBlockPtr( PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const void* BlockPtr);
Normally calling a function in this library with invalid details will cause a trap, this function is designed to test the validity of the block pointer within the block descriptor array.  Calling this function with an invalid array will still cause a trap but if BlockPtr is not valid for a valid block array (supplied) the function returns 1U (true), meaning "yes, this block ptr is bad".  If the block is valid 0U (false) is returned.  To avoid a trap and test an array pointer call dpcrtlmm_IsBadArrayPtr( )

unsigned int dpcrtlmm_IsBadArrayPtr( PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray );
Verifies the validity of a block descriptor array without causing a trap, the return value is 1 (true) if the array pointer is bad, 0 (false) for a good array pointer.  NULL is accepted as a valid array pointer, so is the resolved version but it's unlikely you'll see that unless your code is a hook.

void* dpcrtlmm_Realloc(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, void* OldBlockPtr, const size_t NewSize);
Reallocates a block, equivilant to C runtime library call realloc( ), this is used for resizing a block of memory.  The block array must be specified, it can be NULL to specify the default array.  The pointer to the block of memory to resize should be specified next, followed by the desired new size.  Attempting to resize to 0 is equivillant to dpcrtlmm_Free( ) I rely on your run-time library supporting this bahaviour however, in the next version I want to make sure it will work whether your run-time library supports it or not.  The block of memory might be moved by the operating system's memory manager the return value should be used and replaces OldBlockPtr which should now be considered invalid.  Don't replace your old pointer with the new one until you are sure it is non-zero, if it is NULL the block could not be resized, most probally because there is not enough continuous free memory.  Note that NULL is also returned when a block is freed (providing your run-time library supports it).  If a debug hook is installed it will currently only see the event if the reallocation is successful, therefore the hook routine(s) will only see Success = 1.

void* dpcrtlmm_Calloc(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const unsigned int N, const size_t NewBlockSize);
Equivilant to C run time library calloc( ) purely a wrapper around alloc( N * NewBlockSize ) everything else is the same.  See dpcrtlmm_Alloc( ) for more information

void dpcrtlmm_InstallTrapCallback( void(*UserCallbackProc)(const unsigned int TrapID, const char* TrapMessage), const unsigned int AsHook );
When a trap is fired, the default behaviour of the program is to put the message on stderr and call abort, this behaviour can be changed to call (for example) the Daybo Logic fatal trap handler (which puts up a blue screen), or something like that.  The trap handler takes a constant pointer to a string (const char*), it should not return it should always terminate the program.  Perhaps memory errors could be ignored by not doing so but behaviour of the program afterwards might be undefined.  If the specified function is installed as a hook it is called when a trap is fired but if it returns the default library handler is called anyway.  It just gets a preview.  Do not try to remove a handler by passing NULL to this function, use dpcrtlmm_RemoveTrapCallback( )

void dpcrtlmm_RemoveTrapCallback( void(*CurrentCallbackProc)(const unsigned int TrapID, const char* TrapDesc) );
Removes a trap handler which was installed by dpcrtlmm_InstallTrapHandler( ), must pass address so we know you know and are not making a dreadful mistake, there is no return value.

signed char dpcrtlmm_GetTrapCallbackInfo(void);
Sometimes the user of the library has installed a handler for traps instead of the default library handler, the function returns very simple information about it.  There are three possible values, the other values won't be used.  The three possible values are
-1 for no user trap handler
0 for a handler which is installed as a handler
1 for a handler which acts as a hook.
The important thing about a hook is that it gets preview of the trap but the default one is called afterwards and therefore the hook is expected to return.  A handler should terminate the program, if it returns the default handler will not be called, the user handler has replaced it.  So if a handler returns the program may continue after a trap which could lead to unpredictable results.

unsigned char dpcrtlmm_ModifyDescriptorFlags(const PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const void* Ptr, const unsigned char* PNewFlags);
This function implements direct flag access (not reconmended except for advanced programmers who have the library source so they know the descriptor flag meanings), casual programmers should use the specialist locking functions or other functions which change the flags but don't actually explictly state that is what they are doing, this flag modifying function is usually used by the library internally and not by the users of the library, I have only made it available to the users because of the possibility of unforeseen circumstances arising, it's not very likely that users will need to use this function.

Pass pointer to new flags for the block, old flags are returned, to get the flags without modifying them, pass NULL as the
pointer PNewFlags.  It is feasible that the function could return after a trap if traps are off or a user handler is called for the trap, which returned.  It is not possible to tell, if anything is suspected on running the program, at redesign your code so that it does not use a user trap (just comment out the line installing the handler, or don't turn off trapping).

void dpcrtlmm_SetBlockLockingFlag(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const void* Ptr, const unsigned int NewStatus);
Locks or unlocks a block of memory.  When a block of memory is locked, it means it cannot be freed or resized, if a trap is fired as a result of the call, the function ModifyDescriptorFlags( ) is mentioned as the location of the trap, so don't get confused!
NewStatus is a boolean, nonzero = true, zero = false.

unsigned int dpcrtlmm_IsBlockLocked(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const void* Ptr);
Simply returns the boolean status 1 if the block specified has been locked or 0 if it has not.  When a block is locked, it cannot be freed or resized.

#define dpcrtlmm_LockBlock(pArr, pBlock) dpcrtlmm_SetBlockLockingFlag(pArr, pBlock, (1U));
#define dpcrtlmm_UnlockBlock(pArr, pBlock) dpcrtlmm_SetBlockLockingFlag(pArr, pBlock, (0U));
Both of these functions are simple macros to lock and unlock blocks of memory see dpcrtlmm_SetBlockLockingFlag( )

void dpcrtlmm_ToggleBlockLockingStatus(PS_DPCRTLMM_BLOCKDESCARRAY PBlockArray, const void* Ptr);
If the said block is locked, it will be unlocked and vice versa, not sure if anyone will bother to use this function really

void dpcrtlmm_EnableTraps(void);
See dpcrtlmm_DisableTraps( ), normally only that will be used in a program for the reasons described.  The only reason one might want to use this function is for temporary things say like, disable traps, perform actions, re-enable traps.  Implemented as a macro, see dpcrtlmm__EnableTraps

void dpcrtlmm_DisableTraps(void);
Normally when the library starts traps are enabled, however let's say that the program is massive, a deadline is coming and it must be released.  Although there are a few leaks that can't be tracked down it's stable and users would have nothing to complain about.  They won't be too happy if DPCRTLMM keeps outputting all the mistakes at the end.  Removing the library may not be feasible if the program is designed intimately around it so the answer is to disable the traps, just call this function once after starting the library to avoid traps.  Implemented as a macro, see dpcrtlmm__EnableTraps

unsigned char dpcrtlmm_AreTrapsEnabled(void);
Returns whether traps are enabled or not, 1U means enabled 0U if not.  Implemented as a macro, see dpcrtlmm__EnableTraps

void dpcrtlmm_GetStats(PS_DPCRTLMM_STATS PReadStats);
Returns memory statistics for the library, such as, number of allocated blocks, amount of memory used (charge) and peaks, pass a pointer to the structure to read the data, forgetting to pass the pointer will do absolutely nothing.  Most of the information can be returned directly from internal counts, most statistics are modified at the time they are changed, for example allocating a block would increment the count of blocks and the amount you added would be added to the total allocation charge.  However, because I made it possible to modify the flags of a descriptor I cannot tell how many locks etc. there are, for these I had to implement a nested loop to check the flags of all descriptors, shouldn't reduce performance too much but remember that the function should not be called too often.

unsigned long dpcrtlmm_GetBlockCount(void);
Returns the number of blocks allocated, don't worry I'm not completely mad, the count is stored internally it is not worked out by this function, I don't go mad, looping through all the arrays looking for blocks!

PS_DPCRTLMM_VERSION dpcrtlmm_Ver(PS_DPCRTLMM_VERSION PVerStruct);
Returns library version info, the caller supplies the structure and I return them the same structure, passing NULL does nothing.

extern unsigned char dpcrtlmm__EnableTraps;
This can be used to disable/enable traps, while it is off no trap will be executed and if the program makes a mistake it could crash, if can either be modified directly or with the macros dpcrtlmm_EnableTraps( ), dpcrtlmm_DisableTraps( ) and dpcrtlmm_AreTrapsEnabled( ).  Generally one will want to switch it off when releasing a program, simple start the program with a call to dpcrtlmm_Startup( ) and then set this variable to 0U, the two valid states are 0U = no traps, 1U = traps will be used.  1U is the default.  If you have the absoluetely version (source) this variable is store in dpcrtlmm.c
 

If you want to make sales enquires please contact sales@daybologic.co.uk, for lastest news check the web page and update your documentation & library regularly, remember updates cost nothing.  If you have an equiry of a more technical nature you can contact me directly at Overlord@DayboLogic.co.uk

(C)Copyright 2000 Overlord David Duncan Ross Palmer, Daybo Logic.  This copyright will be defended to th maximum extent of applicable law.  The source is only released for rebuilding or user modifcation purposes for necersary extensions to functionaility.  Modified version resale by purchasers or people who have obtained a registered copy through other means is a copyright violation if if we discover such activity do not assume we will not sue.